原型
執行代碼var o = new Object();
此時o對象內部會存儲一個指針,這個指針指向了Object.prototype,當執行o.toString()
等方法(或訪問其他屬性)時,o會首先查看自身有沒有該方法或屬性,如果沒有的話就沿着內部存儲的指針找到Object.prototype
對象,然后查看Object.prototype
對象是否有對應名稱的方法或屬性,如果有就調用Object.prototype
的方法或屬性。
我們把這個指針叫做o對象的原型。
ES3規范中定義了Object.prototype.isPrototypeOf()方法,該方法可以判斷某個對象是不是另一個對象的原型。Object.prototype.isPrototypeOf(o)
返回true值可以確定Object.prototype就是o對象的原型。
在ES3規范中,不能直接讀取o對象的原型,也就是o對象的原型看不見摸不着的。ES5.1規范定義了Object.getPrototypeOf()方法,通過該方法可以獲取對象的原型。我們可以通過Object.getPrototypeOf(o) === Object.prototype
再次驗證Object.prototype就是o對象的原型。
ES6規范更加直接,為對象添加了一個__proto__
屬性,通過這個屬性就可以獲得對象的原型,所以在支持__proto__
的瀏覽器中,o.__proto__ === Object.prototype
也會返回true。
當我們執行var x = new X();
時,瀏覽器會執行x.__proto__ = X.prototype
,會將實例化對象的原型設置為對應的類的prototype對象,這一點很重要。
原型鏈
我們執行如下代碼:
function Person(){}; var p = new Person();
p.__proto__指向了Person.prototype,Person.prototype的原型是Person.prototype.__proto__,其指向了Object.prototype,Object.prototype.__proto__為null。
通過__proto__向上追蹤形成了如下的鏈式結構:
p -> Person.prototype -> Object.prototype -> null
這一原型的鏈式結構就叫做原型鏈。Object.prototype的原型是null,也就是說Object.prototype沒有原型。
JavaScript 對象有一個指向一個原型對象的鏈。當試圖訪問一個對象的屬性時,它不僅僅在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依此層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。
JavaScript中的繼承是通過原型實現的,雖然在ES6中引入了class
關鍵字,但是它只是原型的語法糖,JavaScript繼承仍然是基於原型實現的。
ES5寄生組合繼承 (業內比較提倡的方法)
function inserit(son, father) { var obj = Object.create(father.prototype); son.prototype = obj; obj.constructor = son } function SuperType(name, colors) { this.name = name; this.colors = colors; } SuperType.prototype.sayName = function () { return this.name; } function SubType(job, name, color) { SuperType.call(this, name, color); this.job = job; } //核心方法 inserit(SubType, SuperType); SubType.prototype.sayjob = function () { return this.job; } var instance = new SubType("doctor", "John", ["red", "green"]); console.log(instance.sayjob(), instance.sayName()) //doctor,John
ES6繼承
ES6
支持通過類來實現繼承,方法比較簡單,代碼如下
class Point { constructor(x, y) { this.x = x this.y = y } toString() { return this.x + '' + this.y } } class ColorPoint extends Point { constructor(x, y, color) { super(x, y) //調用父類的constructor(x, y) this.color = color } toString() { return this.color + ' ' + super.toString() // 調用父類的toString() } } var colorPoint = new ColorPoint('1', '2', 'red') console.log(colorPoint.toString()) // red 12