淺析JS原型鏈

始識發表於2024-03-27

目錄
  • 例項物件
  • 原型物件
  • 物件原型
  • 短暫總結一下
  • constructor
  • 原型鏈

何為原型鏈呢

就是例項物件和原型物件之間的連結,每一個物件都有原型,原型本身又是物件,原型又有原型,以此類推形成一個鏈式結構.稱為原型鏈。

這裡又扯到了另外兩個概念了。

例項物件>>> 先往下看例項物件

原型物件>>> 先往下看 原型物件

例項物件

說到這裡。我們另外再來提一提 另一個東西: 建構函式。那既然提到了建構函式 由不得不提普通函式了。

先來講一下建構函式

建構函式是一種特殊的函式,主要用來初始化物件,即為物件成員變數賦初始值。

例如:

let Num = function Num() {
    this.add = function (a, b) {
        return a + b
    }
}

let n = new Num()
console.log(n.add(1, 2));

這裡例項物件已經出來了。就是在你new 這個 建構函式的時候。就已經建立了例項物件 在本文中 n就是一個例項物件

**這裡簡單說一下例項物件在建立成功時會發生什麼變化。

  1. 在記憶體中建立一個新的空物件;
  2. 讓this指向這個新的物件。這裡this指向問題 我只用一句話就能總結: 誰呼叫this就指向誰
  3. 執行建構函式里面的程式碼,給這個新物件新增屬性和方法;
  4. 返回這個新物件(所以建構函式里面不需要return)。

再來講一下普通函式

普通函式就是.... 就是最普通的函式 例如

function add(a, b) { return a+b };
add(1,2)

雖然上述兩種方式。都能得到結果 3

但是兩種宣告以及使用的方式都不一樣。


那這裡總結下區別

  1. 建構函式首字母要大寫,類似於python中的類
  2. 建構函式是透過new運算子來建立例項物件的,而普通函式則不需要。

這裡還有個點。

例項物件建立成功後 已經有了一個__proto__的內建屬性了。

而建構函式本身有個屬性是prototype 稱之為物件原型

原型物件

原型物件是建構函式上的一個屬性,用來建立公共的方法。也就是prototype

舉個例子。

直接建立個建構函式。然後賦值個方法。

//語法: 建構函式.prototype.方法名 = function() {}
function Animal(name) {
    this.name = name
}

// 賦值公共方法
Animal.prototype.eat = function () {
    console.log(`${this.name}在吃飯`)
}

let dog = new Animal("狗")
let cat = new Animal("貓")
dog.eat()
cat.eat()
console.log(dog.eat === cat.eat)    // true

結果

狗在吃飯
貓在吃飯
true

這裡扯到了 原型物件 那就再講講另一個概念 物件原型。其實這個概念可以忽略不計。

物件原型

**物件原型是例項物件(物件)身上的一個屬性, 該屬性為 _proto_ **

//語法: 建構函式.prototype.方法名 = function() {}
function Animal(name) {
    this.name = name
}

// 賦值公共方法
Animal.prototype.eat = function () {
    console.log(`${this.name}在吃飯`)
}

let dog = new Animal("狗");

console.log(dog.__proto__);
console.log(dog.__proto__ === Animal.prototype);

結果

{ eat: [Function (anonymous)] }
true

短暫總結一下

這裡捋一下關係

  1. 每個建構函式都有一個原型物件 原型物件的(prototype)
  2. __proto__等於其建構函式的prototype,即每個__proto__都指向其建構函式的prototype
  3. 原型物件(prototype) == 物件原型(__proto__)

constructor

construct是原型物件(prototype) 和 物件原型(__proto__)身上的一個屬性

而 constructor會記錄當前物件屬於哪個建構函式。

這裡舉個例子吧、

//語法: 建構函式.prototype.方法名 = function() {}
function Animal(name) {
    this.name = name
}

// 賦值公共方法
Animal.prototype.eat = function () {
    console.log(`${this.name}在吃飯`)
}

let dog = new Animal("狗");

dog.constructor.prototype
console.log(dog.constructor.prototype)

結果 這裡在node中看不出來。我們直接看瀏覽器中的

這裡就很好理解了。

其實 constructor 的出現原本就是用來進行物件型別判斷。任何物件都有constructor屬性。

那你說這個有啥用???

因為我們是搞爬蟲的嗎。肯定是很有用的。

constructor 本來就是用來找到其上層建構函式的。那我們在設定補環境框架。或者是在補環境的時候不就能容易找到最外層的構造環境了嗎?

原型鏈

很好現在基礎概念都懂了。那我們是不是可以重新梳理了一下呢?

我的理解是原型鏈的構成包含了上文我講的的這些部分。

所謂原型鏈的流程(僅本人在補環境中的理解):

當你在尋找一個方法或者屬性。如果該物件自身沒有這個屬性 或者方法。

那這個引擎(JS)就會沿著原型鏈向上去找。直到找到這個屬性 或者方法。

直到到達原型鏈的最頂層也就是我們上文說的Prototype

那話說到這裡。

說白了 原型鏈其實就是JavaScript中用於實現物件繼承的一種機制。

好了 此文完結。懂各種概念就行

相關文章