深入解析JavaScript原型鏈面試題

JavaScript 是一種弱類型、基於原型的編程語言。原型是 JavaScript 的一項非常重要的特性,也是面試中經常考察的知識點。JS 原型鏈是基於原型的面向對象編程的基石,掌握這一知識點對於我們理解 JavaScript 的對象模型非常重要。本文將帶你從多個方面深入剖析JavaScript原型鏈面試題。

一、JS原型鏈基本概念

在 JavaScript 中,每個函數都有一個 prototype 屬性,也就是原型對象。原型對象是一個普通的對象,包含屬性和方法。每個實例對象都通過 __proto__ 屬性引用其構造函數的原型對象 prototype。

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}, I'm ${this.age} years old.`);
}
const person = new Person('Tom', 18);

在以上代碼中,Person 函數有一個 prototype 屬性,它是一個普通的對象,並且包含一個方法 sayHello。person 是使用 Person 函數構造出來的實例對象, 它通過 __proto__ 屬性引用了 Person 的原型對象 Person.prototype,因此它可以使用原型對象中的方法 sayHello。

二、JS原型鏈的構建方式

原型鏈是由每個對象的 __proto__ 屬性構成的。我們可以通過以下方式構建原型鏈:

1. 新建一個構造器函數

2. 擴展構造器的原型對象

3. 使用 new 操作符創建子對象

4. 構造器原型對象的 __proto__ 屬性指向構造器父級的原型對象

5. 子對象的 __proto__ 屬性指向了構造器的原型對象,也就是形成了原型鏈

function Animal(name) {
  this.name = name;
}
Animal.prototype.sayName = function () {
  console.log(this.name);
}

function Dog(name, age) {
  this.age = age;
  Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype); // Dog 繼承 Animal 
Dog.prototype.constructor = Dog; // constructor 指向 Dog 
Dog.prototype.sayAge = function () {
  console.log(this.age);
}

const dog = new Dog('Lily', 1);

在以上代碼中,Dog 繼承了 Animal 的方法以及屬性。通過 Dog.prototype = Object.create(Animal.prototype),Dog 的原型指向了 Animal 的原型,因此它可以使用 Animal 的原型中的方法 sayName,在 Dog 的原型中添加 sayAge 方法。

三、JS原型鏈的查找順序

當我們在一個實例對象上調用一個屬性或者方法時,JavaScript 引擎會按照如下的順序查找屬性或方法:

1. 首先查找實例對象本身是否有該屬性或方法

2. 如果沒有,則查找實例對象的原型對象是否有該屬性或方法

3. 如果還沒有,則查找實例對象原型對象的原型對象是否有該屬性或方法

4. 重複上述步驟,直到查找到 Object 的原型對象,即可結束查找

function Animal(name) {
  this.name = name;
}
Animal.prototype.sayName = function () {
  console.log(this.name);
}

function Dog(name, age) {
  this.age = age;
  Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.sayAge = function () {
  console.log(this.age);
}

const dog = new Dog('Lily', 1);
console.log(dog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true

在以上代碼中,dog 是 Dog 的實例對象。當我們在 dog 上調用 sayAge 方法時,首先查找 dog 本身是否有該方法,發現沒有。然後查找 Dog.prototype 是否有該方法,發現有。因此調用了該方法並輸出了 dog 的年齡。在這個查找的過程中,JS 引擎按照 __proto__ 屬性指向的原型對象繼續查找,直到最後找到 Object 的原型對象 Object.prototype 為止。

四、JS原型鏈的繼承方式

在 JavaScript 中,有很多實現繼承的方法。下面分別介紹一下常用的幾種繼承方式:

1. 構造函數繼承

構造函數繼承是一種常用的繼承方式。其基本思想是在子類的構造函數中調用父類的構造函數。

function Parent(age) {
  this.age = age;
}
function Child(age) {
  Parent.call(this, age);
}
const child = new Child(18);
console.log(child.age); // 18

在以上代碼中,Child 函數的構造函數中調用了 Parent 的構造函數並傳入參數。Child 實例可以訪問到 Parent 實例中的屬性 age。

2. 原型鏈繼承

原型鏈繼承的基本思想是通過將子類的原型對象指向父類的實例對象來實現繼承。

function Parent(age) {
  this.age = age;
}
Parent.prototype.sayAge = function () {
  console.log(this.age);
};
function Child(age) {}
Child.prototype = new Parent(18);
const child = new Child();
console.log(child.age); // 18
child.sayAge(); // 18

以上代碼中,Child 的原型指向了 Parent 的實例,並且 Child 的實例可以訪問到 Parent 中的方法和屬性。

3. 組合繼承

組合繼承是上述兩種繼承方式的結合。其基本思想是通過構造函數繼承實現屬性的繼承,通過原型鏈繼承實現方法的繼承。

function Parent(age) {
  this.age = age;
}
Parent.prototype.sayAge = function () {
  console.log(this.age);
};
function Child(age) {
  Parent.call(this, age);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child(18);
console.log(child.age); // 18
child.sayAge(); // 18

以上代碼中,Child 函數的構造函數中調用了 Parent 的構造函數並傳入參數,實現了屬性的繼承。Child 的原型對象指向了 Parent 的原型對象,並且將 constructor 指向了 Child 函數,實現了方法的繼承。

結語

JavaScript 原型鏈是一種非常重要的特性。理解原型鏈能夠幫助我們更好地理解 JavaScript 的對象模型和繼承機制。掌握 JavaScript 原型鏈的實現方式以及查找順序可以幫助我們更好地回答面試題。在實際項目中,可以根據練習的需求選擇不同的繼承方式以實現需求。

原創文章,作者:XGIKP,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/363902.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
XGIKP的頭像XGIKP
上一篇 2025-03-12 18:48
下一篇 2025-03-12 18:48

相關推薦

  • 使用JavaScript日期函數掌握時間

    在本文中,我們將深入探討JavaScript日期函數,並且從多個視角介紹其應用方法和重要性。 一、日期的基本表示與獲取 在JavaScript中,使用Date對象來表示日期和時間,…

    編程 2025-04-28
  • JavaScript中使用new Date轉換為YYYYMMDD格式

    在JavaScript中,我們通常會使用Date對象來表示日期和時間。當我們需要在網站上顯示日期時,很多情況下需要將Date對象轉換成YYYYMMDD格式的字符串。下面我們來詳細了…

    編程 2025-04-27
  • 源碼審計面試題用法介紹

    在進行源碼審計面試時,可能會遇到各種類型的問題,本文將以實例為基礎,從多個方面對源碼審計面試題進行詳細闡述。 一、SQL注入 SQL注入是常見的一種攻擊方式,攻擊者通過在輸入的參數…

    編程 2025-04-27
  • JavaScript中修改style屬性的方法和技巧

    一、基本概念和方法 style屬性是JavaScript中一個非常重要的屬性,它可以用來控制HTML元素的樣式,包括顏色、大小、字體等等。這裡介紹一些常用的方法: 1、通過Java…

    編程 2025-04-25
  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • CloneDeep函數在Javascript開發中的應用

    一、CloneDeep的概念 CloneDeep函數在Javascript中是一種深層克隆對象的方法,可以在拷貝對象時避免出現引用關係。使用者可以在函數中設置可選參數使其滿足多種拷…

    編程 2025-04-25
  • JavaScript中的Object.getOwnPropertyDescriptors()

    一、簡介 Object.getOwnPropertyDescriptors()是JavaScript中一個非常有用的工具。簡單來說,這個方法可以獲取一個對象上所有自有屬性的屬性描述…

    編程 2025-04-25
  • 深入理解byte轉int

    一、字節與比特 在討論byte轉int之前,我們需要了解字節和比特的概念。字節是計算機存儲單位的一種,通常表示8個比特(bit),即1字節=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25

發表回復

登錄後才能評論