這裡討論下物件的內部原型(__proto__)和構造器的原型(prototype)的關係。
一、所有建構器/函數的__proto__都指向Function.prototype,它是一個空函數(Empty function)
複製程式碼
複製程式碼
複製程式碼
程式碼如下:
Number.__proto__ === Function.prototype // true
Date.__proto__ === Function.prototype // true
JavaScript中有內建(build-in)構造器/物件共12個(ES5中新加了JSON),這裡列舉了可存取的8個構造器。剩下如Global不能直接訪問,Arguments僅在函數呼叫時由JS引擎創建,Math,JSON是以物件形式存在的,無需new。它們的__proto__是Object.prototype。如下
複製程式碼
程式碼如下: Math.__proto__ ===🎜>
Math.__proto__ === true
JSON.__proto__ === Object.prototype // true
上面說的「所有建構器/函數」當然包含自訂的。如下
複製程式碼
程式碼如下:
console.log(Man. __proto__ === Function.prototype) // true
這說明什麼呢?
所有的建構器都來自於Function.prototype,甚至包括根構造器Object及Function自身。所有建構器都繼承了Function.prototype的屬性及方法。如length、call、apply、bind(ES5)。
Function.prototype也是唯一一個typeof XXX.prototype為 “function”的prototype。其它的建構器的prototype都是一個物件。如下
複製程式碼
程式碼如下:
console.log(type Function.prototype) // function
console.log(typeof Object.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof RegExp.prototype) // 是.prototype) // object
console.log(typeof Date.prototype) // object
console.log(typeof Object.prototype) // object
複製程式碼
程式碼如下:
console.log(Function.prototype. = Object.prototype) // true
複製程式碼 程式碼如下: Object.prototype.__proto =__== null // 已經到頂了,為null。 二、所有物件的__proto__都指向其建構器的prototype 上面測試了所有內建建構器及自訂建構器的__proto__,下面再看看所有這些建構器的實例物件的_ _proto__指向誰? 先看看JavaScript引擎內建建構器 複製程式碼 程式碼如下:
var obj = {name: 'jack'}
var arr = [1,2,3]
var reg = /hello/g
var date = new Date
var err = new Error('exception')
console.log(obj.__proto__ === Object.prototype) // true
console.log(arr.__proto__ === Array.prototype) // true
console.log(reg.__proto__ === RegExp.prototype) // true
console.log(date.__proto__ === Date.prototype) // true
console.log(err.__proto__ === Error.prototype) // true
再看自訂的構造器,這裡定義了一個Person
function Person(name) {
this.name = name
}
var p = new Person('jack ')
console.log(p.__proto__ === Person.prototype) // true
p是Person的實例對象,p的內部原型總是指向其建構器Person的prototype。
每個物件都有constructor屬性,可以取得它的建構器,因此以下列印結果也是恆等的
function Person(name) {
this.name = name
}
var p = new Person('jack')
console .log(p.__proto__ === p.constructor.prototype) // true
上面的Person沒有給其原型添加屬性或方法,這裡給其原型添加一個getName方法
function Person(name) {
this.name = this.name> 🎜>}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('jack')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
可以看到p.__proto__與Person.prototype, p.constructor.prototype都是恆等的,即都指向同一個物件。
如果換個方式設定原型,結果就有些不同了
程式碼如下:
程式碼如下:
程式碼如下:
function Person(name) {
this.name = name
}
// 重寫原型
這裡直接重寫了Person.prototype(注意:上一個範例是修改原型)。輸出結果可以看出p.__proto__仍然指向的是Person.prototype,而不是p.constructor.prototype。
這也很好理解,給Person.prototype賦值的是一個物件直接量{getName: function(){}},使用物件直接量方式定義的物件其構造器(constructor)指向的是根構造器Object,Object.prototype是一個空物件{},{}自然與{getName: function(){}}不等。如下
複製程式碼
上面程式碼中用到的__proto__目前在IE6/7/8/9中都不支援。 IE9中可以使用Object.getPrototypeOf(ES5)來取得物件的內部原型。
複製程式碼 程式碼如下: var p .getPrototypeOf(p) console.log(__proto__ === Object.prototype) // true