目錄
1. 定義
Object.prototype
屬性表示Object
的原型對象。
2. 原理
準確的說:所有的原型對象都是Object構造函數創建的,Object.prototype除外;所有函數都是Function的實例,包括Function本身和Object。
我們創建的每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。
function Person() {
}
Person.prototype.name = 'CoolSummer';
Person.prototype.age = '30';
Person.prototype.printName = function(){
console.log(this.name)
}
var person1 = new Person();
person1.printName();//'CoolSummer'
var person2 = new Person2();
person2.printName();//'CoolSummer'
console.log(person1.printName === person2.printName);//true
看了很多的介紹原型的資料,我認爲最好的是來自Nicholas.C.Zakas的《JavaScript高級程序設計》(第三版)中的圖例
這張圖完美解釋了構造函數、原型和對象實例三者的關係,Person構造函數有一個prototype屬性,這個屬性指向構造函數的原型,構造函數的原型有一個constructor屬性,指向構造函數,由這個構造函數派生出的對象實例Person1,Person2等內部有一個[[Prototype]]槽,這個槽指向構造函數的原型。另外這個[[Prototype]]槽在ECMAScript2015後可以通過Obeject.getProtypeOf()拿到這個值。不同的瀏覽器存在差異,在有些瀏覽器中可以通過對象實例._proto_屬性拿到構造函數的原型對象。
不再推薦通過對象實例._proto_屬性拿到構造函數的原型對象。儘管某些瀏覽器可能仍支持它,但是它可能已經從相關的Web標準中刪除,正在被刪除或僅出於兼容性目的而保留。避免使用它,並儘可能更新現有代碼;請參閱此頁面底部的兼容性表以指導您做出決定。請注意,此功能可能隨時停止起作用。
雖然
Object.prototype.__proto__
今天大多數瀏覽器都支持該功能,但它的存在和確切行爲僅在ECMAScript 2015規範中被標準化爲一項傳統功能,以確保與Web瀏覽器的兼容性。爲了獲得更好的支持,建議Object.getPrototypeOf()
改爲使用。
//瀏覽器兼容性IE9+/FireFox3.5+/Safari5+/Openera12+/Chrome
console.log(Object.getPrototypeOf(person1) === Person.prototype);// true,
原型對象的優點是:所有的對象實例都可以共享它包含的屬性和方法。這一點可以在構造函數裏就可以看出來,因爲構造函數在函數裏面就定義了對象的實例信息,而原型對象可以在任何地方定義屬性和方法。
原型對象的缺點有點像:“成也蕭何,敗也蕭何”。原型對象最大的缺點就是它的共享本性造成的。這種共享對於原型構造內部的函數來說,沒什麼影響,但是對於屬性來說問題就比較多了。如一個對象實例中設置了原型對象的值,那麼其他的對象實例中的值也會改變。
3. 用法
1、使用構造函數(或者class)創建對象
由於原型的優點和缺點都是由於共享特性,所以我們使用原型創建對象時要儘量只在構造函數中定義方法,屬性要從外部傳入。
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
上面的class當成是function即可,這其實也是一種組合使用構造函數和原型創建對象的模式。
2、動態原型模式創建對象
function Person(name, age){
this.name = name;
this.age = age;
if(typeof this.printName != 'function'){
Person.prototype.printName = function(){
print(thi.name);
}
}
}
var person = new Person('CoolSummer', 30);
person.printName();//'CoolSummer'
var person2 = new Person('sky', 20);
person2.printName();//'sky'
4. 拓展
4.1 instanceof
instanceof
運算符用於檢測構造函數的 prototype
屬性是否出現在某個實例對象的原型鏈上。
function instanceof (left, right){
let prototype = right.prototype;
left = left._proto_;
while(true){
if(left === null){
return false;
}
if(left === portotype){
return true;
}
left = left.prototype;
}
}
4.2 ES6 class
ECMAScript 2015(ES6)中引入的class主要是對JavaScript現有的基於原型的繼承的語法糖。類語法不會向JavaScript引入新的面向對象的繼承模型。
5. 參考資料
2. MDN class
3. Nicholas.C.Zakas的《JavaScript高級程序設計》(第三版)---紅寶書