忘掉了不要緊!再來一遍JavaScript原型鏈

1.原型的概念

先提出一個問題:將函數定義在全局做用域,會污染全局做用域的命名空間(接下來起了個同名函數就會覆蓋),並且很是不安全(別人一塊兒寫時,也可能會寫同樣名字的函數)。 怎麼辦? ——將這些函數放到原型對象中去。那麼什麼是原型對象?javascript

咱們所創建的每個函數,解析器都會向函數中添加一個屬性prototype,這個屬性對應着一個對象,這個對象就是原型對象。java

  • 若是函數做爲普通函數調用prototype沒有任何做用意義。
  • 當函數以構造函數的形式調用時,它所建立的對象中都會包含一個隱含屬性,指向構造函數的原型對象,實例中咱們能夠經過__proto__來訪問該屬性。
  • 同一個類對應的原型對象是同一個,原型對象至關於一個公共的區域,全部同一個類的實例均可以訪問到這個原型對象,因此咱們能夠將對象共有的東西統一設置到原型對象裏。

例子:安全

function Person(){
}//這樣以普通函數形式定義的,首字母大寫的,
//使用時使用new調用的就是構造函數
var per1=new Person();
var per2=new Person();
console.log(per1.__proto__==per2.__proto__);//輸出true
因此同一個構造函數的實例共有一個原型對象。
複製代碼

在原型對象中設置屬性: 例子:markdown

function Person(){
//這樣以普通函數形式定義的,首字母大寫的,
//使用時使用new調用的就是構造函數
//其與普通函數的區別就是要使用new
//這裏爲了方便使用空函數
}
var per2=new Person();
Person.prototype.a=123;
console.log(per2.a);//輸出123
per2是Person的實例,因此能夠訪問Person對象下的原型函數。
複製代碼

上面的Person.prototype.a=123;就是將a屬性設置到了Person構造函數的原型函數裏。函數

2.原型鏈

1.原型鏈圖解

圖:實例原型鏈 在這裏插入圖片描述ui

先寫一段代碼(而後再使用代碼來驗證其中的關係)this

/注意:下面對象的原型函數 和 其建立的原型函數是不一樣的/

/在Object建立的原型鏈中建立一個函數/
Object.prototype.print=function(){
    console.log("我在Object下的原型對象中");
};
/在Object的原型對象中建立一個函數/
Object.__proto__.print3=function(){
    console.log('我在Object的原型對象中');
}
/建立一個Fun構造函數,這個Fun實際上也是全局下一個普通函數/
function Fun(x,y){
    this.x=x;
    this.y=y;
}
/在Fun建立的原型函數下建立一個函數/
Fun.prototype.print2=function(){
    console.log('Fun類下的原型對象');
}
/使用Fun構造函數來建立一個a實例,a實例屬於Fun類下/
var a=new Fun(1,2);
複製代碼

2.理清例子中的原型鏈

  • 原型鏈相關的語法(圖中用foo,咱們這裏定義的是fun

使用構造函數建立一個實例,與該實例一塊兒被建立的還有原型函數,該原型函數在該類下只有一個,該1類的實例共用一個原型函數。 實例使用實例對象.__proto__來訪問對原型函數進行讀寫操做。 構造函數(Object和Fun使用對象.prototype來訪問其建立的原型函數)spa

  • Fun和Object的關係
/注意:這裏的代碼是承接上面的那一段代碼的,下面同理/
console.log(Fun===Object);
//false,Fun和Object是兩個不一樣的構造函數
console.log(Fun.__proto__===Object.__proto__);
//true,其共用一個原型對象
console.log(Fun.__proto__.print3());
//我在Object的原型對象中
複製代碼

Fun和Object是同級別的,共用一個原型鏈。prototype

  • Fun和Object它們對應的原型對象
console.log(Fun.__proto__===Object.__proto__);
//輸出true
console.log(Function.__proto__==Fun.__proto__);
//輸出true
console.log(Object.__proto__);
//輸出{ print3: [Function (anonymous)] }
console.log(Object.__proto__.__proto__);
//輸出[Object: null prototype] { print: [Function (anonymous)] }
console.log(Object.__proto__.__proto__.__proto__);
//輸出null
複製代碼

說明Object和Fun上有一個共用的原型對象,該原型對象上還有一個空原型對象,再往上就爲空了3d

  • Fun和Object其各自建立的原型對象的關係
console.log(Fun.prototype==Object.prototype);
//false
console.log(Fun.prototype.constructor==Fun);
//true
console.log(Object.prototype.constructor==Object);
//true
console.log(Fun.prototype.constructor.__proto__==Object.__proto__);
//true
複製代碼

說明兩個構造函數各類建立的原型對象不是同一個。並且構造函數下的原型對象的構造函數就是其自己,證實了 在這裏插入圖片描述

  • a與Fun的關係
console.log(Object.print3());
//我在Object的原型對象中
console.log(Fun.print3());
//我在Object的原型對象中
console.log(a.print3());
//a.print3 is not a function
console.log(a.__proto__.constructor==Fun);
//true
console.log(a.__proto__.constructor==a.constructor);
//true
console.log(a.constructor==Fun);
//true
console.log(a.constructor==Fun.prototype);
//false
console.log(a.__proto__==Fun.prototype);
//true
console.log(a.print());
//我在Object建立的原型對象中
console.log(a.print2());
//Fun類建立的原型對象中
console.log(Function.__proto__==Fun.__proto__);
//true
複製代碼

能夠看出a和Fun是實例與構造函數的關係,a沒法訪問到object.__proto__

  • a與Object的關係
console.log(a.constructor.__proto__==Object.__proto__);
//true
複製代碼

這裏用代碼捋了捋關係,但沒講完精髓,請再看後面!

3.再走一遍原型鏈

這裏爲原型鏈標上序號(注意函數下的函數的表達區別) 帶序號的原型鏈 先本身分析一遍,明白了就跳過下面內容,直接離開。

  • 序號1:Foo構造函數的實例f1其的原型對象是構造函數Foo下的原型對象,也就是f1.__proto__==Foo.prototype,而Foo下的原型對象也是經過Foo構造函數建立的實例,因此其與f1同級,構造函數Function同理。

在這裏插入圖片描述 在這裏插入圖片描述

  • 序號2:是對象就有原型對象(不是死循環,到object的prototype爲止),構造函數Foo下建立的原型對象的原型對象是指向object.prototype的,Foo的實例共有的原型對象是Foo.prototype,而各大構造函數的構造函數下的原型對象的原型對象是object下的原型對象。
  • 在這裏插入圖片描述
  • 序號3:這裏就印證了序號2介紹的第一句話,object.prototype是終端,object是大長老。

在這裏插入圖片描述

  • 序號4:到這裏就是開始了最重要的部分,由於這裏開始出現了function這各構造函數,這裏先不講,留到5來講,Object構造函數的實例o1的原型對象是object.prototype,object的構造函數時function。

在這裏插入圖片描述

  • 序號5:大膽下結論,一切構造函數的爸爸(構造函數)都是function。object是function的實例,function是最特殊的,object的原型對象是function下的原型對象,而function.prototype.__proto__又是object.prototype。還有就是Function.__proto__ == Function.prototype

理解的鑰匙:function 是關鍵字,Function 是引用類型。使用function建立的變量是一個指針,指向的對象是一個Function對象。下面有三種函數聲明方式,

//第一種:
function a (){};
//第二種:
var a = function(){};
//第三種:
var a = new Function();
複製代碼

在這裏插入圖片描述

  • 序號6:Function.prototype.__proto__==Object.prototype,就像序號2介紹中說的各大構造函數的構造函數下的原型對象的原型對象是object下的原型對象。

在這裏插入圖片描述

感謝閱讀,若是有更好的理解歡迎留言!

相關文章
相關標籤/搜索