首頁  >  文章  >  web前端  >  JavaScript如何模擬實作new關鍵字? (附代碼)

JavaScript如何模擬實作new關鍵字? (附代碼)

不言
不言轉載
2018-11-12 16:34:262793瀏覽

本篇文章帶給大家的內容是關於JavaScript如何模擬實作new關鍵字? (附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

最近工作太忙,快接近兩週沒更新博客,總感覺有一些事情等著自己去做,雖然工作內容對自己提升挺大,但我總覺得,一直埋著頭走路,偶爾也需要抬起頭來,看看現在和自己的期望向是否脫軌,所以週末還是選擇來星巴克寫些文字。

今天記錄JavaScript 中new 關鍵字的模擬實現,當我們在模擬實現某個語言行為之前,應該想想這個行為都做了哪些事情,透過實踐,最後也能更加掌握知識點,這就是許多面試問題都會問到模擬實現的原因,目的是為了檢視候選人知識的深度。

function Person(name) {
    this.name = name;
}
var person = new Person('jayChou');
typeof(person)  // "object"
person instanceof Person  // true
person.__proto__ === Person.prototype  // true
person.constructor === Person  //  true
person.constructor === Person.prototype.constructor  // true

以上,可以看出:

  1. new 建立並傳回了一個新對象,是建構函式的實例

  2. 物件的實例的建構子屬性其實是建構子的原型物件的constructor 屬性

  3. 物件實例的 __proto__ 關聯到建構函數的原型物件

#上面的內容有關於JavaScript 中原型物件和原型鏈的知識,不夠清楚的同學可以查看我之前的部落格。

由於 new 是 JS 的一個關鍵字,我們無法實作關鍵字,但我們可以透過函數的形式來模擬 new 關鍵字的行為。

一、基本想法

知道 new 關鍵字做了哪些工作,那我們就有了模擬實作的基本想法。

/**
 * 模拟实现 JavaScript new 操作符
 * @param  {Function} constructor [构造函数]
 * @return {Object|Function|Regex|Date|Error}      [返回结果]
 */
function mockNew() {
    // 创建一个空对象
    let resultObj = new Object();

    // 取传入的第一个参数,即构造函数,并删除第一个参数。
    let constructor =  Array.prototype.shift.call(arguments);
    
    // 类型判断,错误处理
    if(typeof constructor !== "function") {
        throw("构造函数第一个参数应为函数");
    }
    
    // 绑定 constructor 属性
    resultObj.constructor = constructor;
    
    // 关联 __proto__ 到 constructor.prototype
    resultObj.__proto__ = constructor.prototype;
    
    // 将构造函数的 this 指向返回的对象
    constructor.apply(resultObj, arguments);
    
    // 返回对象
    return resultObj;
}

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


var person = mockNew(Person, "jayChou");

console.log(person);

// constructor: ƒ Person(name)
// name: "jayChou"
// __proto__: Object

基本想法正確!所以我們完成了 new 關鍵字的初步模擬。夥伴們可以自己打一下,每句程式碼自己是否都能理解。

二、處理回傳值

建構函數也是函數,有不同型別回傳值。有時候建構函數會傳回指定的物件內容,所以要對這部分進行處理。

/**
 * 模拟实现 JavaScript new 操作符
 * @param  {Function} constructor [构造函数]
 * @return {Object|Function|Regex|Date|Error}      [返回结果]
 */
function mockNew() {
    // 创建一个空对象
    let emptyObj = new Object();

    // 取传入的第一个参数,即构造函数,并删除第一个参数。
    // 关于为什么要用 Array.prototype.shift.call 的形式,见之前的博客文章 《JavaScript之arguments》
    let constructor =  Array.prototype.shift.call(arguments);
    
    // 类型判断,错误处理
    if(typeof constructor !== "function") {
        throw("构造函数第一个参数应为函数");
    }
    
    // 绑定 constructor 属性
    emptyObj.constructor = constructor;
    
    // 关联 __proto__ 到 constructor.prototype
    emptyObj.__proto__ = constructor.prototype;
    
    // 将构造函数的 this 指向返回的对象
    let resultObj = constructor.apply(emptyObj, arguments);
    
    // 返回类型判断, 如果是对象,则返回构造函数返回的对象
    if (typeof resultObj === "object") {
        return resultObj
    }
    
    // 返回对象
    return emptyObj;
}

function Person(name) {
    this.name = name;
    return {
        name: this.name,
        age: 40
    }
}


var person = mockNew(Person, "jayChou");

console.log(person);

// {name: "jayChou", age: 40}
// age: 40
// name: "jayChou"
// __proto__: Object

當傳回值傳回了一個自訂物件後,模擬 new 函數就會傳回該自訂物件。

總結

JavaScript new 關鍵字的意義在於讓普通函數產生一個新對象,並將物件實例的 __proto__ 關聯到函數的 prototype 物件。

本文有些地方需要一些前置知識,但是整體上理解是比較容易的。

#

以上是JavaScript如何模擬實作new關鍵字? (附代碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除