JavaScript New模擬實現

New幹了什麼

(1) 建立一個新對象;
(2) 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象) ;
(3) 執行構造函數中的代碼(爲這個新對象添加屬性) ;
(4) 綁定原型;
(4) 返回新對象。
注意:數組

  • 若是構造函數有返回的值而且爲基本類型的話則沒有影響,返回值毫無心義;
  • 若是返回值的類型爲object,那這個返回值會被正常使用
function Test(name) {
  this.name = name
  return 1
}
const t = new Test('yck')
console.log(t.name) // 'yck'


function Test(name) {
  this.name = name
  console.log(this) // Test { name: 'yck' }
  return { age: 26 }
}
const t = new Test('yck')
console.log(t) // { age: 26 }
console.log(t.name) // 'undefined'

實現方式

由於 new 是關鍵字,因此沒法直接覆蓋,因此咱們寫一個函數,命名爲 myNew,來模擬 new 的效果。用的時候是這樣的:app

function person() {
    ……
}

// 使用 new
var person = new person(……);
// 使用 objectFactory
var person = myNew(person, ……)

實現過程

由於 new 的結果是一個新對象,因此在模擬實現的時候,咱們也要創建一個新對象,假設這個對象叫 obj,由於 obj 會具備 Otaku 構造函數裏的屬性,想一想經典繼承的例子,咱們能夠使用 Otaku.apply(obj, arguments)來給 obj 添加新的屬性。函數

function myNew() {
//用new Object() 的方式新建了一個對象 obj
    var obj = new Object(),
//取出傳入的構造函數。此外由於shift會修改原數組,因此arguments會被去除第一個參數
    Constructor = [].shift.call(arguments);
//將 obj 的原型指向構造函數,這樣 obj 就能夠訪問到構造函數原型中的屬性
    obj.__proto__ = Constructor.prototype;
//使用 apply,改變構造函數 this 的指向到新建的obj對象,並執行了Constructor,這樣obj就會被添加屬性
     var ret = Constructor.apply(obj, arguments);
//判斷返回的值是否是一個對象,若是是一個對象,咱們就返回這個對象,若是不是,咱們原樣返回    
    return typeof ret === 'object' ? ret : obj;
//返回出去
    return obj;
};

驗證myNew

function person(name, age) {
    this.name = name;
    this.age = age;

    this.habit = 'Games';
}

person.prototype.strength = 60;

person.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}


var person = myNew(person, 'Kevin', '18')

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60

person.sayYourName(); // I am Kevin

New的其餘簡潔寫法

function myNew(Con, ...args) {
  let obj = {}
//等同於 obj.__proto__ = Con.prototype
  Object.setPrototypeOf(obj, Con.prototype)
  let result = Con.apply(obj, args)
  return result instanceof Object ? result : obj
}
相關文章
相關標籤/搜索