1. 程式人生 > >原型鏈問題之 __proto__

原型鏈問題之 __proto__

警告: 通過現代瀏覽器的操作屬性的便利性,可以改變一個物件的 [[Prototype]] 屬性, 這種行為在每一個JavaScript引擎和瀏覽器中都是一個非常慢且影響效能的操作,使用這種方式來改變和繼承屬性是對效能影響非常嚴重的,並且效能消耗的時間也不是簡單的花費在 obj.__proto__ = ... 語句上, 它還會影響到所有繼承來自該 [[Prototype]] 的物件,如果你關心效能,你就不應該在一個物件中修改它的 [[Prototype]].。相反, 建立一個新的且可以繼承 [[Prototype]]

 的物件,推薦使用 Object.create()

警告: 當Object.prototype.__proto__ 已被大多數瀏覽器廠商所支援的今天,其存在和確切行為僅在ECMAScript 2015規範中被標準化為傳統功能,以確保Web瀏覽器的相容性。為了更好的支援,建議只使用 Object.getPrototypeOf()

Object.prototype 的 __proto__  屬性是一個訪問器屬性(一個getter函式和一個setter函式), 暴露了通過它訪問的物件的內部[[Prototype]]

 (一個物件或 null)。

使用__proto__是有爭議的,也不鼓勵使用它。因為它從來沒有被包括在EcmaScript語言規範中,但是現代瀏覽器都實現了它。__proto__屬性已在ECMAScript 6語言規範中標準化,用於確保Web瀏覽器的相容性,因此它未來將被支援。它已被不推薦使用, 現在更推薦使用Object.getPrototypeOf/Reflect.getPrototypeOf 和Object.setPrototypeOf/Reflect.setPrototypeOf(儘管如此,設定物件的[[Prototype]]是一個緩慢的操作,如果效能是一個問題,應該避免)。

__proto__ 屬性也可以在物件文字定義中使用物件[[Prototype]]來建立,作為Object.create()的一個替代。 請參閱: object initializer / literal syntax.

let Circle = function () {};
let shape = {};
let circle = new Circle();
 
// 設定該物件的原型鏈引用
// 過時且不推薦使用的。這裡只是舉個例子,儘量不要在生產環境中這樣做。
shape.__proto__ = circle;

// 判斷該物件的原型鏈引用是否屬於circle
console.log(shape.__proto__ === circle); // true
let shape = function () {};
let p = {
    a: function () {
        console.log('aaa');
    }
};
shape.prototype.__proto__ = p;

let circle = new shape();
circle.a();//aaa
console.log(shape.prototype === circle.__proto__);//true

//或者
let shape = function () {};
var p = {
    a: function () {
        console.log('a');
    }
};

let circle = new shape();
circle.__proto__ = p;
circle.a(); //  a
console.log(shape.prototype === circle.__proto__);//false

//或者
function test() {}
test.prototype.myname = function () {
    console.log('myname');
}
let a = new test()
console.log(a.__proto__ === test.prototype);//true
a.myname();//myname

//或者
let fn = function () {};
fn.prototype.myname = function () {
    console.log('myname');
}

let obj = {
    __proto__: fn.prototype
};

obj.myname();//myname

注意:這是兩個下劃線,後面是五個字元的 “proto” ,後面再跟兩個下劃線。

描述

_proto__的讀取器(getter)暴露了一個物件的內部 [[Prototype]] 。對於使用物件字面量建立的物件,這個值是 Object.prototype。對於使用陣列字面量建立的物件,這個值是 Array.prototype。對於functions,這個值是Function.prototype。對於使用 new fun 建立的物件,其中fun是由js提供的內建構造器函式之一(ArrayBooleanDateNumberObjectString 等等),這個值總是fun.prototype。對於用js定義的其他js構造器函式建立的物件,這個值就是該構造器函式的prototype屬性。

__proto__ 的設定器(setter)允許物件的 [[Prototype]]被變更。前提是這個物件必須通過Object.isExtensible() 判斷為是可擴充套件的,如果不可擴充套件,則會丟擲一個 TypeError 錯誤。要變更的值必須是一個object或null,提供其它值將不起任何作用。

要理解原型如何被使用,請檢視相關文章:Inheritance and the prototype chain

.__proto__屬性是Object.prototype 一個簡單的訪問器屬性,其中包含了get(獲取)和set(設定)的方法,任何一個__proto__的存取屬性都繼承於Object.prototype,但一個訪問屬性如果不是來源於Object.prototype就不擁有.__proto__屬性,譬如一個元素設定了其他的.__proto__屬性在Object.prototype之前,將會覆蓋原有的Object.prototype