JavaScript專題之模擬實現new

本文共 1230 字,讀完只需 5 分鐘javascript

寫在前面java

最近工做太忙,快接近兩週沒更新博客,總感受有一些事情等着本身去作,雖然工做內容對本身提高挺大,但我總以爲,一直埋着頭走路,偶爾也須要擡起頭來,看看如今和本身的指望向是否脫軌,因此週末仍是選擇來星巴克寫些文字。面試

今天記錄 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
複製代碼

以上,能夠看出:app

  1. new 建立並返回了一個新對象,是構造函數的實例
  2. 對象的實例的構造函數屬性實際上是構造函數的原型對象的 constructor 屬性
  3. 對象實例的 __proto__ 關聯到構造函數的原型對象

上面的內容有關於 JavaScript 中原型對象和原型鏈的知識,不夠清楚的同窗能夠查看我以前的博客。函數

因爲 new 是 JS 的一個關鍵字,咱們沒法實現關鍵字,但咱們能夠經過函數的形式來模擬 new 關鍵字的行爲。post

1、基本思路

知道 new 關鍵字作了哪些工做,那咱們就有了模擬實現的基本思路。ui

/** * 模擬實現 JavaScript new 操做符 * @param {Function} constructor [構造函數] * @return {Object|Function|Regex|Date|Error} [返回結果] */
function mockNew() {
    // 建立一個空對象
    let resultObj = new Object();

    // 取傳入的第一個參數,即構造函數,並刪除第一個參數。
    // 關於爲何要用 Array.prototype.shift.call 的形式,見以前的博客文章 《JavaScript之arguments》
    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 關鍵字的初步模擬。夥伴們能夠本身動手敲一下,每句代碼本身是否都能理解。this

2、處理返回值

構造函數也是函數,有不一樣類型返回值。有時候構造函數會返回指定的對象內容,因此要對這部分進行處理。spa

/** * 模擬實現 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 系列文章

  1. JavaScript之變量及做用域
  2. JavaScript之聲明提高
  3. JavaScript之執行上下文
  4. JavaScript之變量對象
  5. JavaScript之原型與原型鏈
  6. JavaScript之做用域鏈
  7. JavaScript之閉包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值傳遞
  11. JavaScript之例題中完全理解this
  12. JavaScript專題之模擬實現call和apply
  13. JavaScript專題之模擬實現bind

歡迎關注個人我的公衆號「謝南波」,專一分享原創文章。

相關文章
相關標籤/搜索