深入理解JavaScript的原型物件
阿新 • • 發佈:2019-01-01
JavaScript的繼承機制是基於原型,而不是類。因此要理解JavaScript的繼承機制,需要更深入瞭解原型物件。
先區分一下基於原型的常見寫法:
這3種寫法prototype,getPrototypeOf和__proto__之間的不同:
C.prototype:用於引用new C()建立的物件的原型物件
Object.getPrototypeOf(obj):是獲取obj物件的原型物件的標準方法
obj.__proto__:是獲取obj物件的原型物件的非標準方法
示意程式碼:
上面都是自解釋程式碼,一看就能明白。通過C.prototype形式,可以獲得原型物件,為之新增屬性或方法。ES5環境下通過Object.getPrototypeOf(obj)可以檢查現有物件的原型。一些環境提供了非標準的方法檢索物件的原型,即特殊的屬性__proto__,可以在不支援Object.getPrototypeOf方法時作為權宜之計。function Person(name, age) { this.name = name; this.age = age; } Person.prototype.sayName = function(){ alert(this.name); } var p1 = new Person("Jack", 32); var p2 = new Person("Zhang", 30); p1.sayName(); //Jack p2.sayName(); //Zhang Object.getPrototypeOf(p1) === Person.prototype //true Object.getPrototypeOf(p2) === Person.prototype //true p1.__proto__ === Person.prototype //true p2.__proto__ === Person.prototype //true
(儘可能用Object.getPrototypeOf,而不要用__proto__,詳細原因可以參見《Effective JavaScript》的<Item 31: Prefer Object.getPrototypeOf to __proto__>,簡單地說__proto__是非安全的)
如何實現繼承呢?
通過原型鏈來模擬其他OO語言中的繼承。先回顧一下上一篇文章中介紹過的建構函式和原型物件和例項物件間的關係:
每個建構函式內部均有一個prototype原型指標,指向該型別的原型物件C.prototype。原型物件C.prototype中包含一個回指向建構函式的指標constructor。這樣就實現了建構函式和原型物件間的雙向繫結。每個例項物件內部也包含一個指向原型物件C.prototype的指標。
現在用原型鏈來實現JavaScript的繼承:
示意圖://定義父類Person,建構函式內有兩個屬性name和age,原型物件內定義了sayName方法 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.sayName = function(){ alert(this.name); } //定義子類Man,讓其模擬繼承父類 Personfunction Man(name, age){ Person.call(this, name, age); //子類中呼叫父類的建構函式 this.gender = "male"; //子類中定義個新屬性gender } Man.prototype = new Person(); //繼承是通過建立父類的原型物件,並將子類的prototype指標指向該原型物件來實現的 Man.prototype.constructor = Person; Man.prototype.sayGender = function (){ alert(this.gender); }; var m1 = new Man("Jack", 32); m1.sayName(); //Jack m1.sayGender(); //male var m2 = new Man("Zhang", 30); m2.sayName(); //Zhang m2.sayGender(); //male alert(m1 instanceof Object); //true,顯然建立的例項物件,既是Object,也是Person,也是Man alert(m1 instanceof Person); //true alert(m1 instanceof Man); //true alert(Object.prototype.isPrototypeOf(m1)); //true alert(Person.prototype.isPrototypeOf(m1)); //true alert(Man.prototype.isPrototypeOf(m1)); //true