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