先提出一個問題:將函數定義在全局做用域,會污染全局做用域的命名空間(接下來起了個同名函數就會覆蓋),並且很是不安全(別人一塊兒寫時,也可能會寫同樣名字的函數)。 怎麼辦? ——將這些函數放到原型對象中去。那麼什麼是原型對象?javascript
咱們所創建的每個函數,解析器都會向函數中添加一個屬性prototype,這個屬性對應着一個對象,這個對象就是原型對象。java
__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構造函數的原型函數裏。函數
圖:實例原型鏈 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);
複製代碼
使用構造函數建立一個實例,與該實例一塊兒被建立的還有原型函數,該原型函數在該類下只有一個,該1類的實例共用一個原型函數。 實例使用實例對象.__proto__
來訪問對原型函數進行讀寫操做。 構造函數(Object和Fun使用對象.prototype
來訪問其建立的原型函數)spa
/注意:這裏的代碼是承接上面的那一段代碼的,下面同理/
console.log(Fun===Object);
//false,Fun和Object是兩個不一樣的構造函數
console.log(Fun.__proto__===Object.__proto__);
//true,其共用一個原型對象
console.log(Fun.__proto__.print3());
//我在Object的原型對象中
複製代碼
Fun和Object是同級別的,共用一個原型鏈。prototype
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
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
複製代碼
說明兩個構造函數各類建立的原型對象不是同一個。並且構造函數下的原型對象的構造函數就是其自己,證實了
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__
console.log(a.constructor.__proto__==Object.__proto__);
//true
複製代碼
這裏用代碼捋了捋關係,但沒講完精髓,請再看後面!
這裏爲原型鏈標上序號(注意函數下的和函數的表達區別) 先本身分析一遍,明白了就跳過下面內容,直接離開。
f1.__proto__==Foo.prototype
,而Foo下的原型對象也是經過Foo構造函數建立的實例,因此其與f1同級,構造函數Function同理。
Function.__proto__ == Function.prototype
理解的鑰匙:function 是關鍵字,Function 是引用類型。使用function建立的變量是一個指針,指向的對象是一個Function對象。下面有三種函數聲明方式,
//第一種:
function a (){};
//第二種:
var a = function(){};
//第三種:
var a = new Function();
複製代碼
Function.prototype.__proto__==Object.prototype
,就像序號2介紹中說的各大構造函數的構造函數下的原型對象的原型對象是object下的原型對象。感謝閱讀,若是有更好的理解歡迎留言!