我對js原型鏈的理解

2021-07-11 10:43:55 字數 4573 閱讀 3883

引言

從關鍵字new 說起

我來試著模擬一下new的操作過程。

//模擬new關鍵字的行為

function methodnew( func ) //func:新物件的建構函式

; //{}實際上等價於object()

obj.constructor = func; //更改obj的constructor屬性

obj.__proto__ = func.prototype; //設定obj.__proto__屬性,從而訪問到原型鏈上的屬性,

//比如 func.prototype.name可以通過 obj.name讀取,但是不能使用obj.name來修改,這樣會為obj新增乙個name屬性。

//這裡只處理func方法引數為空的情況

func.call( obj ); //為obj新增func方法中定義的屬性,比如

//function func()

//相當於執行obj.name = "jerry"

return obj;

}}

來測試一下

function

people()}

var obj = methodnew( object );

var beauty = methodnew( people );

console.log( obj );

console.log( beauty );

結果如下

object

{}people

結果與new關鍵字生成的物件一致。

稍微總結一下,new關鍵字的行為與後面的方法是不是object()有關,

非object()方法時,執行下面四步

1.

var obj = {}; //生成乙個object物件

2. obj.constructor = func; //設定constructor,由此判斷物件的型別由constructor屬性決定

3. obj.__proto__ = func.prototype; //這一步很關鍵,將obj連入原型鏈,從而能訪問func.prototype物件以及它的原型鏈上端物件的屬性

4. func.call( obj ); //為obj新增func()方法中宣告的屬性

這裡我把__proto__放在前面,因為它是原型鏈的基礎。

people.prototype

.hobby = "籃球"

;people.prototype

.swim = function();

var obj = {};

obj.__proto__ = people.prototype

;console.log( obj.hobby );

obj.swim

;

物件訪問屬性的順序是先查詢自身,顯然hobbyswim都不是obj自身的屬性,這是系統會查詢obj.__proto__指向的物件是否有這兩個屬性,這裡就是people.prototype,如果還沒有,會繼續找people.prototype.__proto__指向的物件有沒有所需屬性,這裡有乙個知識點,宣告乙個函式people()時,people.prototype屬性指向誰呢?

根據我的研究,函式的prototype屬性的初始化很簡單,分為兩步

1. people.prototype = {}; //將乙個object物件賦給prototype

2. people.prototype.constructor = people; //設定constructor為people,表示原型物件的型別是people

因為people.prototype是乙個普通的object物件,所以有

people.prototype.__proto__指向object.prototype,

這與圖中的描述是吻合的。

如此一來,下面的原型鏈就形成了

obj−→

−−−−

−−−__proto__ 

people.prototype−→

−−−−

−−−__proto__ 

object.prototype−→

−−−−

−−−__proto__ 

null

有一條對原型鏈文章的評價:js物件其實就是鍵值對,說的不錯,js中的方法和變數都以物件的形式存在,乙個物件能訪問到的其實就是自己的屬性原型鏈上的屬性

看看下面的例子

people.prototype

.hobby = "籃球"

;people.prototype

.swim = function();

var obj = {};

obj.__proto__ = people.prototype

; obj.hobby );

;obj.hobby = "撩妹"

;console.log( people.prototype

.hobby );

發現結果仍然是籃球,說明這裡是為obj新增了自己的hobby屬性,並沒有改動原型物件的屬性。

我們再做進一步測試

people.prototype

.sing = function()

var obj = {};

obj.song = "愛的供養"

;obj.__proto__ = people.prototype

;obj.sing();

people.prototype

.sing

.call( obj );

//結果

//愛的供養*2

這一步解釋了原型物件中的方法是怎麼被執行的。

圖中functionobject的關係比較令人費解,其實可以這麼理解。

js中所有的物件都是由函式通過new操作符生成的,比如

var obj = new people()

則一定有obj.__proto__ == people.prototype'

而所有的函式物件都是由function()函式生成的,object()方法也不例外,所以有

object.__proto__ = function.prototype

當然,function()方法也是由自己生成的,所以推出

function.__proto__ = function.prototype

(其實object()方法和function()方法都是本地**(native code),也就是事先寫好的,並不是生成的物件,原型鏈中這樣設計是為了邏輯的完備)。

這裡比較特殊的兩個物件是function.prototypeobject.prototype,這兩個物件的生成不符合上面提到的規律

1. people.prototype = {}; 

2. people.prototype.constructor = people;

function.prototype作為function的原型物件是由function()函式直接返回的,並不是乙個object物件,而且這個屬性是唯讀的,它的值顯示如下

function empty() {}

從邏輯上來說, 所有的函式物件也應該能訪問object.prototype的屬性,所以有

function.protototype.__proto__ = object.prototype

讓所有的函式物件通過function.prototype訪問原型鏈的末端object.prototype

作為原型鏈的尾端,object.prototype的屬性可以被js中的所有物件訪問,object.prototype__proto__是唯讀的,這保證了object.prototype作為原型鏈的乙個出口。

我對js原型和原型鏈的用法

優點 1.資料共享 節約記憶體記憶體空間 2.實現繼承 我們知道在js中,萬物皆物件,物件可以說是重中之重了。每乙個物件都擁有自己的屬性。但是在這個世界中有很多東西都是相似的,可以歸為一類,他們有共同的方法和屬性。不可能讓每乙個物件都定義乙個屬性吧。那樣太消耗記憶體了。所以,在js中怎麼才能讓多個物...

對JS原型機原型鏈的理解

使用建構函式建立物件 function person var person1 newperson person1.name 張三 console.log person1.name 張三 person就是乙個建構函式,通過new建立了person1物件例項。其實建構函式和普通函式沒有多大區別,首先字母...

js 原型 原型鏈理解

執行發現如下 自定義乙個函式,函式包含兩個關鍵資料 prototype,proto 1 原型 prototype person具有prototype屬性 包含我們定義的屬性name,age以及constructor,並且constructor指向我們的person函式,可以理解為prototype就...