先提出一個問題:將函數定義在全局做用域,會污染全局做用域的命名空間(接下來起了個同名函數就會覆蓋),並且很是不安全(別人一塊兒寫時,也可能會寫同樣名字的函數)。
怎麼辦?
——將這些函數放到原型對象中去。那麼什麼是原型對象?javascript
咱們所創建的每個函數,解析器都會向函數中添加一個屬性prototype,這個屬性對應着一個對象,這個對象就是原型對象。java
__proto__
來訪問該屬性。例子:安全
function person(){ } var per1=new person(); var per2=new person(); console.log(per1.__proto__==per2.__proto__);//輸出true 因此同一個構造函數的實例共有一個原型對象。
在原型對象中設置屬性:
例子:函數
function person(){ } var per2=new person(); person.prototype.a=123; console.log(per2.a);//輸出123 per2是person的實例,因此能夠訪問person對象下的原型函數。
上面的person.prototype.a=123;
就是將a屬性設置到了person構造函數的原型函數裏。this
圖:實例原型鏈
spa
先寫一段代碼(而後再使用代碼來驗證其中的關係)prototype
/注意:下面對象的原型函數 和 其建立的原型函數是不一樣的/ /在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
來訪問其建立的原型函數)3d
/注意:這裏的代碼是承接上面的那一段代碼的,下面同理/ console.log(Fun===Object); //false,Fun和Object是兩個不一樣的構造函數 console.log(Fun.__proto__===Object.__proto__); //true,其共用一個原型對象 console.log(Fun.__proto__.print3()); //我在Object的原型對象中
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上有一個共用的原型對象,該原型對象上還有一個空原型對象,再往上就爲空了code
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 a (){}; //第二種: var a = function(){}; //第三種: var a = new Function();
Function.prototype.__proto__==Object.prototype
,就像序號2介紹中說的各大構造函數的構造函數下的原型對象的原型對象是object下的原型對象。感謝閱讀,若是有更好的理解歡迎留言!