通俗易懂的理解js原型鏈

js的原型鏈

爲什麼需要原型鏈?

  • 爲什麼需要原型:在一些場景中,比如人類行爲有些要打遊戲,有些要上學,有些要工作,但同時他們都需要喫飯和睡覺,但如果把每個人喫飯睡覺私有化使用的話就有點浪費內存,這時候就可以把這些每個人都需要做的行爲統一拿出來放到一個公共的空間,每個人都有權限訪問它,這樣就可以節省內存。而實現共享的,這個時候就用到了原型 prototype。可以將附加屬性附加到它,這些屬性將在其構造函數的所有實例之間共享。

什麼是原型鏈?

  • 瞭解原型鏈之前先來了解一下js創建對象的過程
    https://www.cnblogs.com/geekjsp/p/15807618.html

  • 訪問一個對象時,js引擎內部的查找過程,會按以下順序進行查找:

    • 1.首先在自身的對象查找,如果有,就返回。
    • 2.如果對象自身沒有,就去對象所屬的構造函數進行查找,如果有就返回。
    • 3.如果在對象所屬的構造函數中沒有找到,就去構造函數的原型(鏈)上進行查找。
    • 4.如果在整個原型鏈都查找完畢時,仍然找不到目標屬性,就會返回undefined。
   
   function Bar() {
       this.color = "red"
   }
   
   Bar.prototype.color = "green";
   let obj = new Bar();
   obj.color = "blue";
   
   console.log(obj.color);    // blue
   

   demo2:印證上述第二點:

   function Bar() {
       this.color = "red"
   }
   
   Bar.prototype.color = "green";
   let obj = new Bar();
   
   console.log(obj.color);    // red
   

   demo3:印證上述第三點

   function Bar() {
   
   }
   
   Bar.prototype.color = "green";
   let obj = new Bar();
   
   console.log(obj.color);    // green
   

   demo4:印證上述第四點

   function Bar() {
   
   }
   
   let obj = new Bar();
   
   console.log(obj.color);    // undefined

  

prototype和[[prototype]]有什麼關係?

其實[[prototype]]和__proto__意義相同,均表示對象的內部屬性,其值指向對象原型。前者在一些書籍、規範中表示一個對象的原型屬性,後者則是在瀏覽器實現中指向對象原型。

prototype是函數纔有的屬性,Object沒有

原型鏈過程

請看下面的代碼片段:


   function Person(){}
   Person.__proto__==Function.prototype  //true

   let a={}
   a.__proto__==Object.prototype     //true

   let Teacher=new Person();
   Teacher.__proto__==Person.prototype //true

   --------------------------------------------------------

   function test99(){}
   test99.__proto__==Object.prototype
   //true

   test99.__proto__==Function.__proto__
   //false

  ---------------------------------------------------------

   var one = {x: 1};
   var two = new Object();
   one.__proto__ === Object.prototype // true
   two.__proto__ === Object.prototype // true
   one.toString === one.__proto__.toString // true
   說明 one.等於one.__proto__.

  ---------------------------------------------------------

   let objP = function() {};
   let obj = new objP();

   創建一個obj對象  把obj對象的__proto__指向prototype  
   對象的__proto__屬性是創建對象時自動添加的,默認值爲其構造函數的prototype

   因此:
   objP.prototype.sayHell=function(str){console.log(str)}
   let obj = new objP();
   obj.__proto__   //{sayHell: ƒ, constructor: ƒ}
   obj.sayHell('搞懂js原型鏈')
   obj.方法名的時候會到__proto__上找因此會到objP.prototype
   --------------------------------------------------------


   function test666(){}
   let test7=new test666()
   test7.__proto__===test666.prototype
   //true
   test7.__proto__.__proto__===test666.prototype.__proto__
   //true
   test666.prototype.__proto__==Object.prototype
   //true
   Object.__proto__.__proto__
   //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
   Object.__proto__.__proto__.__proto__
   //null

   --------------------------------------------------------

   
   var fn =function (){};
   prototype是在定義函數時自動添加的, 默認值是一個空Object對象
   fn.prototype
   // {constructor: ƒ}
   // constructor: ƒ Person()
   // [[Prototype]]: Object

   可以添加屬性和方法,這些屬性和方法將在其構造函數的所有實例之間共享   
   fn.prototype.name='wen';
   fn.prototype.age='18';

   var obj1=new fn();
   var obj2=new fn();
   console.log(obj1.name);
   console.log(obj2.age);

   obj1.constructor.prototype==fn.prototype

   obj1.name的查找過程:
   obj1> 構造函數fn > fn.__proto__>fn.__proto__.__proto__>null 返回undefined

   --------------------------------------------------------



原型鏈總結

  • 大多數情況下,__proto__可以理解爲“構造函數的prototype”。

  • 每當您在 JavaScript 中訪問對象的屬性時,它首先會檢查該屬性是否在對象內部可用。如果不是,它檢查它的原型對象。如果它在那裏那麼好,你會得到財產的價值。否則,它將檢查該屬性是否存在於原型的原型中,如果不存在則再次檢查該屬性是否存在於原型的原型中,依此類推。

那麼它會以這種方式檢查多長時間?__proto__如果在任何點找到該屬性或在任何點的值爲null或,它將停止undefined。然後它會拋出一個錯誤,通知你它無法找到你正在尋找的屬性。(https://www.freecodecamp.org/news/all-you-need-to-know-to-understand-javascripts-prototype-a2bff2d28f03/)

console.log(Object.prototype.proto===null);//true

原型鏈原理圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章