若是再被問到原型和原型鏈......

求職過程當中,常常會被問到關於原型和原型鏈,就問題自己而言並不難,主要是考察對JavaScript核心概念的理解,但如何可以說明白確實須要認真準備下。node

我印象比較深入的一次,有個面試官出了一道面試題,大意以下:面試

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

let person = new Person('yuyongyu');

複製代碼

請講講person和Object的關係,形式不限。bash

我當時下意識地脫口而出:Object在person的原型鏈上。當時從面試官複雜的表情能夠推斷出這不是他真正想要的答案,但我也基本能夠判定他真實的意圖就是想考察下對原型鏈的掌握,並且指望看到原型鏈的全貌。掌握了出題人的意圖,那接下來就好辦了。函數

過後整理當時的思路以下:學習

簡約版

第一步:person與Person的關係

  • person是對象,對象都有原型(也叫原型指針),指向構造函數的原型對象。

此處即person的__proto__屬性指向Person的prototype。ui

注:__proto__最初是一個非標準屬性,ES6已將其標準化,能夠用標準方法Object.getPrototypeOf()替代,本文出於舉例的直觀性考慮,仍採用此屬性。this

第二步:Person與Function的關係

  • Person是構造函數,構造函數也是函數,函數也是對象,函數除了有原型對象外,也有原型指針。
  • 函數都是由Function構造出來的,故函數的原型指針指向Function的原型對象。

此處即Person的__proto__屬性指向Function的prototype。spa

第三步:Function本身構建本身

  • Function是內建構造函數,內建構造函數也仍是函數,除了有原型對象外,也有原型指針。
  • 函數都是由Function構造出來的,Function做爲函數,是由其自身構建出來,故Function的原型指針指向其自身的原型對象。

此處即Function的__proto__屬性指向Function的prototype。prototype

第四步:Function與Object的關係

  • Function的原型對象,其自己是對象,故其原型指針指向Object的原型對象

此處即Function.prototype的__proto__屬性指向Object的prototype。設計

爲更加直觀表示,做示意圖以下:

以上爲推導過程,必須代碼驗證,結果以下(node環境,ES6版):

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

let person = new Person('yuyongyu');

//第一步驗證
console.log(person.__proto__ === Person.prototype); // true

//第二步驗證
console.log(Person.__proto__ === Function.prototype); // true

//第三步驗證
console.log(Function.__proto__ === Function.prototype); // true

//第四步驗證
console.log(Function.prototype.__proto__ === Object.prototype); // true
複製代碼

至此基本達到了面試官的要求,但過後思考,整個過程過於簡略,還能夠進一步擴展,豐富整個過程。過後擴展思路以下:

豪華版

第一步:person與Person

  • 同上。

第二步:Person.prototype

  • Person的原型對象(prototype)也是對象,除了有原型指針:proto,還擁有構造器屬性:constructor。
  • 函數的原型對象的原型指針(proto)指向Object的原型對象
  • 函數的原型對象的構造器屬性(constructor)指向自身。

此處即Person.prototype的__proto__屬性指向Object的prototype;Person.prototype的constructor屬性指向Person。

第三步:Function.prototype

  • Function的原型對象和Person的原型對象同樣,再也不贅述。

此處即Function.prototype的constructor屬性指向Function;Function.prototype的__proto__屬性指向Object的prototype。

第四步:Object展開

  • Object做爲JavaScript中的內建構造函數,一樣擁有原型指針和原型對象。
  • Object既然是函數,故其原型指針指向Function的原型對象。
  • Object的原型對象一樣包含構造器屬性:constructor和原型指針。
  • Object的原型對象的構造器屬性指向自身。
  • Object的原型對象的原型指針指向null。

此處即Object的__proto__屬性指向Function的prototype;Object.prototype的constructor屬性指向Object;Object.prototype的__proto__屬性指向null.

示意圖以下(虛線僅表明不交叉,無特殊含義):

代碼驗證結果以下:

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

let person = new Person('yuyongyu');

//第一步驗證
console.log(person.__proto__ === Person.prototype); // true
console.log(person.constructor === Person); // true

//第二步驗證
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype.constructor === Person); // true
console.log(Person.prototype.__proto__ === Object.prototype);// true

//第三步驗證
console.log(Function.__proto__ === Function.prototype); // true
console.log(Function.prototype.constructor === Function);
console.log(Function.prototype.__proto__ === Object.prototype);

//第四步驗證
console.log(Object.__proto__ === Function.prototype); // true
console.log(Object.prototype.constructor === Object); // true
console.log(Object.prototype.__proto__ === null); // true
複製代碼

點睛

注意到上圖中那個紅色的null了嗎?

JavaScript到處皆對象,而原型鏈的盡頭居然是null,不禁到想到一句佛語:萬物皆空

若是從反向來看,是null衍生出了豐富多彩的JavaScript世界,不禁得又想到了一句道語:一輩子二,二生三,三生萬物

另外,由上圖可知Object.proto === Function.prototype,Function.prototype.proto === Object.prototype,即Object做爲內建函數由Function構造出來,Function做爲內建構造函數又是對象(函數都是對象),這彷佛又進入了**「雞生蛋和蛋生雞」**的哲學範疇。

因而可知JavaScript的設計思想可謂博大精深,難免感慨JavaScript的學習任重道遠。

相關文章
相關標籤/搜索