JavaScript 中的原型原來是這樣的

2021-09-24 09:15:01 字數 3816 閱讀 3057

原型其實就是乙個特殊的物件,在宣告函式的時候自動建立的。

比如,我們現在宣告乙個建構函式 a ,除了會申請儲存函式的記憶體空間,還會額外申請乙個記憶體空間,用於儲存建構函式 a 的原型物件。所有函式中(function.prototype.bind 除外)預設都有乙個prototype的屬性,它儲存了函式的原型物件的位址(引用)(也就是它指向了原型物件)。 而在原型物件中預設有乙個constructor屬性儲存了建構函式的位址(引用)(也就是constructor指向了建構函式)。如果不理解上面所說的,那我們看下面的圖:

瀏覽器控制台中:

剛開始接觸原型的時候這兩個東西很容易就搞混了。

先記住以下兩點,就很容易就區分了:

我們已經知道了函式中的prototype屬性指向的是它的原型物件,那麼物件中的__proto__代表什麼?

一般情況下,物件中的__proto__屬性是指向它的建構函式的原型物件的,即和建構函式中的prototype屬性所指向的物件是同乙個物件。

用一段簡單的**:

function

a() {}

var a = new a()

複製**

上圖看著不夠簡便,我們簡化一下:

還有一點,__proto__不是乙個規範屬性,ie(除了 ie10) 不支援。對應的標準屬性是[[prototype]],但是這個屬性我們沒法直接訪問到。開發者盡量不要用這種方式去訪問,因為操作不慎會改變這個物件的繼承原型鏈。

在使用object.create(引數)方式建立物件時,物件的__proto__屬性指向的是傳入的引數。

由於__proto__是所有物件都具有的屬性,而__proto__本身指向的原型(函式.prototype)也是乙個物件,它也有__proto__屬性。所以這樣會形成由__proto__物件原型連起來的鏈條。這就是原型鏈。原型鏈的頂端是object.prototype(object 是所有物件的祖宗) ,object.prototype.__proto__的值為null

還是看之前的**:

function

a() {}

var a = new a()

複製**

它的原型鏈如下:

建構函式 a 其實也是乙個物件。所有函式都是由function函式構造的。(宣告函式function a() {}等價於var a = new function()) 。所以所有函式的__proto__指向的都是function.prototype。更新上圖:

function也是乙個函式,它的__proto__指向的也是functon.prototypefuntion.__proto__ === function.prototype。繼更新上圖:

object同樣是乙個函式,所以object.__proto__ === function.prototype

到了這裡,我們應該可以看懂下面這張圖了:

當 js 引擎查詢物件屬性時,先查詢物件本身是否存在該屬性,如果不存在,會在物件的__proto__裡找,還找不到就會沿著原型鏈一直找到原型鏈頂端(object.prototype)直到找到屬性為止,最後在原型鏈頂端都沒找到就返回undefined

由於上面的機制,原型的作用就很明顯了——共享屬性,節省記憶體空間。

function

animal()

}var a1 = new animal()

var a2 = new animal()

console.log(a1.eat === a2.eat) // false

// 每個物件的 eat 方法不是同乙個,但方法類容一樣,浪費記憶體

複製**

使用原型解決:

function

animal(name)

animal.prototype.eat = function()

var a1 = new animal()

var a2 = new animal()

console.log(a1.eat === a2.eat) //true

// a1.eat 和 a2.eat 都同是乙個方法(animal.prototype.eat)

複製**

原型非常適合封裝共享的方法。但是上面的**把建構函式和原型分開寫了。封裝不到位。使用動態型別模式解決。

function

animal()

}}var a = new animal()

a.eat()

複製**

原型基於之前的共享屬性和方法,是實現 js 中繼承的基礎。

通過之前的學習,我們知道了去訪問乙個物件的屬性時,會在原型鏈上查詢。所以我們並不知道這個屬性來自**。

hasownproperty()方法返回乙個布林值,可以判斷乙個屬性是否來自物件本身。

function

animal() {}

animal.prototype.name = '動物'

var a = new animal()

a.age = 3

console.log(a.hasownproperty('name')) // false

console.log(a.hasownproperty('age') // true

複製**

in操作符用返回乙個布林值,用來判斷乙個屬性能否在物件上找到。在物件的原型鏈上找到也返回true

function

animal

() {}

animal.prototype.name = '動物'

var a = new animal()

a.age = 3

console.log('name'

in a) // true

console.log('age'

in a) // true

console.log('***'

in a) // false

複製**

閱讀原文

JavaScript中的原型和原型鏈

上面的圖看懂了麼,沒懂不要緊。先看個栗子 function foo foo.prototype.name haha const foo new foo const bar new foo console.log foo.name haha console.log bar.name haha 複製 沒...

javascript中的原型物件

function person person.prototype.name kobe person.prototype.age 23 person.prototype.job player person.prototype.sayname function var person1 new perso...

JavaScript系列 深入之從原型到原型鏈

本文詳情 建構函式建立物件 先使用建構函式建立乙個物件 function person var person new person person.name mit console.log person.name 在這個例子中,person 就是乙個建構函式,我們使用 new 建立了乙個例項物件 pe...