再回家之前,先new個物件吧

Hdove發表於2020-01-19

接著上一篇,我們繼續來研究如何手寫。

一、手寫new

1.new運算子都做了什麼

  1. 新建一個物件。
  2. 執行prototype連線。
  3. 將建構函式的作用域賦給新物件。
  4. 繫結this指向,執行建構函式中的程式碼。
  5. 返回這個物件。

2.簡單實現


function myNew(context) {

    // 新建一個物件
    var res = new Object();
    
    // 獲取傳遞的引數,第一個引數代表傳入的建構函式,也就是這個即將建立的這個例項的建構函式,擷取掉
    const args = [...arguments].slice(1);
  
    // 將建立的res的this繫結到傳進來的這個建構函式context
    context.apply(res, args);
  
    return res;
}

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

var example = myNew(Hdove, 'LJ');

console.log(example); // {name: "LJ"}

複製程式碼

3.繼續改造

來,我們先看一下真實的new操作符


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

Hdove.prototype.age = 25;

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

var obj = new Hdove('LJ');

console.log(obj.name); // LJ
console.log(obj.age); // 25
obj.sayName(); // LJ

複製程式碼

繼續修改我們的程式碼


function myNew(context) {

    var res = new Object();
    
    // 判斷建構函式上有沒有原型,有的話進行新增
    if(context.prototype) {
        res.__proto__ = context.prototype
    }
    
    const args = [...arguments].slice(1);
  
    context.apply(res, args);
  
    return res;
}

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

Hdove.prototype.age = 25;

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

var example = myNew(Hdove, 'LJ');

console.log(example);

通過下圖我們可以看出原型已經成功繫結了,完美

複製程式碼
再回家之前,先new個物件吧

距離成功還有一步,我們加足馬力

4.改造升級

我們繼續看一下原生的new 操作符

1.返回一個物件
function Hdove(name) {
  this.name = name;
  return {
    name: 'return出來的'
  }
}

var obj = new Hdove('LJ');  
console.log(obj); // {name: "return出來的"}

2.返回基本型別
function Hdove(name) {
  this.name = name;
  return '123';
}


var obj = new Hdove('LJ');  
console.log(obj); // {name: "LJ"}

3.返回一個方法
function Hdove(name) {
  this.name = name;
  return function() {
    console.log(123);
  };
}


var obj = new Hdove('LJ');  
console.log(obj); // function () { window.runnerWindow.proxyConsole.log(123); }

複製程式碼

有沒有發現神奇的事情發生了,當我們在建構函式中返回一個物件型別A的時候,這個時候我們使用new操作符,實際上返回的就是這個A,反之,返回的是我們新建的這個物件,開始實現!


function myNew(context) {

    var res = new Object();
    
    // 判斷建構函式上有沒有原型,有的話進行新增
    if(context.prototype) {
        res.__proto__ = context.prototype
    }
    
    const args = [...arguments].slice(1);
  
    const ret = context.apply(res, args);
    
    // 判斷ret 是不是object或者function,因為null也屬於object,所以要單獨排除
    if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
      return ret;
    }
    return res;
}

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

function Hdove2(name) {
  this.name = name;
  return {
    name: 'return出來的資料'
  }
}

var example1 = myNew(Hdove1, 'LJ');
var example2 = myNew(Hdove2, 'LJ');

console.log(example1); // { name: LJ }
console.log(example2); // { name: return出來的資料 }

複製程式碼

5.完整版


function myNew(context) {

    var res = new Object();
    
    if(context.prototype) {
        res.__proto__ = context.prototype
    }
    
    const args = [...arguments].slice(1);
  
    const ret = context.apply(res, args);
    
    if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
      return ret;
    }
    return res;
}

複製程式碼

6.推薦閱讀

再回家之前,先new個物件吧

相關文章