頭疼的原型對象和原型鏈
我想不少剛接觸Javascript的新手對於原型對象(prototype)和原型鏈(
__proto__
)的區別和含義都表示真尼瑪操蛋,下面就讓我來結合簡單的例子來讓你徹底明白什麼是原型對象,什麼是原型鏈。
prototype和__proto__
的區別
不要想那麼多,你先要知道prototype是函數纔有的屬性,
__proto__
是所有對象都有的屬性。
var person = { name:'test',age:'20'}
console.log(person.prototype) // 輸出undefined
console.log(person.__proto__) // 輸出Object {}
function fun(){console.log("fun")}
console.log(fun.prototype) // 輸出Object {}
console.log(fun.__proto__) // 輸出function () {}
什麼是原型對象(prototype)?
原型對象的用途是爲每個實例對象存儲共享的方法和屬性。通俗的講,一個對象的原型對象是被繼承自它的對象共享的,如B繼承自A,當訪問B中的屬性時,會先找B自己的實例屬性,找不到就會到A的原型對象裏面去找。注意,B不會去自己的原型對象裏面去找,也不會去A的實例屬性集合中找,讓我們看個例子就明白了:
function Person(){
this.name = "Person";
this.age = 100;
}
Person.printName = function(){ //存於Person的實例屬性中
console.log(this.name);
}
Person.prototype.printAge = function(){ //存於Person的原型對象中
console.log(this.age);
}
Person.prototype.name = "oPerson"; //存於Person的原型對象中
console.log(Person.name); //"Person"
console.log(Person.printName); //printName函數,因爲printName屬於Person的實例屬性
console.log(Person.printAge); //undefined,說過了對象不會訪問自己的原型對象的
var person = new Person();
person.prototype.age = 50; // 這樣寫是會報錯的,因爲person不是一個函數,所以沒有原型對象
console.log(person.name); // "Person",person繼承自Person,自然也繼承了name和age屬性
console.log(person.age); // "100",person繼承自Person,自然也繼承了name和age屬性
person.printAge(); //100,person中沒有找到就去Person的原型對象裏面找咯
person.printName(); //報錯,person實例屬性中沒有,Person原型對象中也沒有,我能怎麼辦?
什麼是原型鏈(__proto__
)?
上面說了,如果B繼承自A,那麼訪問B的屬性時,就會依次查找B的實例屬性和A的原型對象,那麼問題來了?B怎麼知道自己的上一級是誰?肯定要用個變量存起來吧?這個變量就是
__proto__
,一個對象的__proto__
指向上一級的prototype,兩者是完全相等的。Object的__proto__
爲null。那麼什麼是原型鏈?我們知道B的__proto__
指向A的prototype,A的__proto__
指向Object的prototype,Object的__proto__
指向null,這樣一串B->A->Object的鏈子就叫原型鏈!
person.__proto__ === Person.prototype // true,可見兩者是完全相同的
Person.__proto__ === Function.prototype // true,可見Person繼承自Function