淺談 JavaScript 原型鏈

在這裏插入圖片描述


原文出自:https://www.pandashen.com


概述

在 JavaScript 中有種說法叫 “萬物皆對象”,就是說無論是構造函數創建的實例,構造函數本身、原型對象、數組、函數本質上都是對象,都擁有 __proto__ 屬性,即隱式原型,所有函數都擁有 prototype 屬性,即顯式原型(僅限函數),原型對象(prototype 屬性指向的對象),在定義函數時就被創建。


原型鏈指向概述

在 JavaScript 中整個原型鏈及查找機制用下圖可以完整的表示出來:

在這裏插入圖片描述

原型鏈指向:

1、通過字面量和 new Object() 所創建的對象,他們是構造函數是 function Object() 的實例,Object 構造函數的 prototype 指向原型對象 Object.prototypeObject.prototypeconstructor 指向構造函數 Object,而實例的 __proto__ 也指向 Object.prototypeObject.prototype__proto__ 指向 null,所以 Object.prototype 也叫做頂級原型對象。

2、上圖中 new Foo() 創建的對象是構造函數 function Foo() 的實例,Fooprototype 指向原型對象 Foo.prototypeFoo.prototypeconstructor 指向構造函數 Foo,而實例的 __proto__ 也指向 Foo.prototype,並且 Foo.prototype 雖然是原型對象,但也是對象,所以是構造函數 Object 的實例,__proto__ 指向頂級原型對象 Object.prototype

3、數組的構造函數是 function Array() 原型鏈的指向與其他除 Object 以外的構造函數相同,Array.prototype__proto__ 也指向頂級原型對象 Object.prototype,每一個數組都是 Array 的實例,__proto__ 都指向 Array.prototype

4、ObjectArrayFoo 等構造函數的本質也是對象,他們的構造函數是 function Function()Functionprototype 指向 Function.prototypeFunction.prototypeconstructor 指向 Function,所有的構造函數的 __proto__ 都指向 Function.prototype,包括 Function 本身,也就是說構造函數 Function 是由自己構造的,Function.prototype__proto__ 同樣指向頂級原型對象 Object.prototype


prototype 原型對象

prototype 是函數的一個屬性,屬性的值指向了一個對象,所以,只有函數纔有 prototype 原型對象。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

typeof Person.prototype; // object
Person.prototype.constructor; // Person {}
Person.prototype.job = "qianduan";

var p1 = new Person("panda", 18);
var p2 = new Person("shen", 20);

p1.constructor.prototype; // 實例對象查找構造函數原型對象的方法

一般會把對象共有的屬性和方法都放在構造函數的原型對象上。


實例、構造函數、原型對象的關係

構造函數的原型 prototype 屬性指向一個原型對象,實例也可以通過 __proto__ 指向原型對象,但本質上實例和構造函數之間是沒有關係的。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

var p = new Person("nihao", 16);
p.constructor = { name: "haha" };
p.name; // nihao

上面的代碼中改變了構造函數的值爲一個對象,對象中的屬性 name 並沒有影響實例的 name 屬性值。


實例屬性 __proto__

上面訪問實例 p 的原型,實際使用 p.constructor.prototype 去找原型對象,當構造函數的值改變後是找不到原型對象的,所以實例並不是通過 constructor.prototype 去查找原型對象的,而是通過每一個實例都有的 __proto__ 屬性,這個屬性指向創建實例的構造函數原本的原型對象,這個屬性不是標準,在 IE 下不存在。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.job = "qianduan";
var p = new Person("nihao", 16);

p.__proto__.job; // qianduan

當構造函數的 prototype 屬性值被改變之後,在之前創建的實例的 __proto__ 屬性值的仍然引用原型對象,所以對構造函數改變前創建的實例是沒有影響的,會影響後面創建的實例。


原型鏈查找機制

實例對象在調用了一個屬性或方法時,如果對象本身沒有這個屬性或方法,會去自己的原型對象查找,也就是 __proto__ 中查找,如果原型對象中沒有,去原型對象的原型對象查找,一般(原型鏈沒有被修改)情況下就是去 __proto____proto__ 中查找,即頂級原型對象 Object.prototype,如果實例對象本身有這個屬性,則直接輸出,不再向上查找,如果對象本身和原型對象具有同名屬性,則會屏蔽掉原型對象的屬性。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.job = "qianduan";
var p = new Person("nihao", 16);

p.job; // qianduan
p.job = "houtai";
p.job; // houtai
p.__proto__.job; // qianduan


總結

原型鏈的指向及原型鏈的查找機制是 JavaScript 中非常重要的基礎知識,理解原型鏈是更深入瞭解繼承和麪向對象編程的必經之路。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章