首頁  >  文章  >  web前端  >  JavaScript中__proto__與prototype的關係深入理解_基礎知識

JavaScript中__proto__與prototype的關係深入理解_基礎知識

WBOY
WBOY原創
2016-05-16 17:47:26855瀏覽

這裡討論下物件的內部原型(__proto__)和構造器的原型(prototype)的關係。
一、所有建構器/函數的__proto__都指向Function.prototype,它是一個空函數(Empty function)

複製程式碼



複製程式碼



複製程式碼


程式碼如下:


Number.__proto__ === Function.prototype // true
Boolean.__proto__ === Function.prototype // true String.proto__ === Function.prototype // true Object.__proto__ === Function.prototype // true Function.__proto__ === Function.prototype // true Array.__proto__ === Function. prototype // true RegExp.__proto__ === Function.prototype // true Error.__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


上面說的「所有建構器/函數」當然包含自訂的。如下



複製程式碼


程式碼如下:
// 函數宣告function Person(> {} // 函數表達式var Man = function() {} console.log(Person.__proto__ === Function.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 Number.prototype) // object console.log(typeof Boolean.prototype) // object console.log(typeof Boolean.prototype) // object console.log(typeof Boolean.prototype) // object .log(typeof String.prototype) // object console.log(typeof Array.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) // 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
這說明所有的構造器也都是一個普通JS對象,可以給構造器添加/刪除屬性等。同時它也繼承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。 最後Object.prototype的__proto__是誰?
複製程式碼 程式碼如下: 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 = { getName: function() {} } var p = new Person('jack') console.log(p.__proto__ === Person.prototype) // true console.log(p.__proto__ === p. constructor.prototype) // false
這裡直接重寫了Person.prototype(注意:上一個範例是修改原型)。輸出結果可以看出p.__proto__仍然指向的是Person.prototype,而不是p.constructor.prototype。
這也很好理解,給Person.prototype賦值的是一個物件直接量{getName: function(){}},使用物件直接量方式定義的物件其構造器(constructor)指向的是根構造器Object,Object.prototype是一個空物件{},{}自然與{getName: function(){}}不等。如下



複製程式碼

程式碼如下: var p = {} console. (Object.prototype) // 為一個空的物件{} console.log(p.constructor === Object) // 物件直接量方式定義的物件其constructor為Object console.log(p .constructor.prototype === Object.prototype) // 為true,不解釋

上面程式碼中用到的__proto__目前在IE6/7/8/9中都不支援。 IE9中可以使用Object.getPrototypeOf(ES5)來取得物件的內部原型。


複製程式碼 程式碼如下: var p .getPrototypeOf(p) console.log(__proto__ === Object.prototype) // true
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn