JS基礎源碼之手寫模擬new
- 手寫模擬new
- 初步實現
- 最終實現
手寫模擬new
new 運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象類型之一。
我們先看看new實現了哪些功能:
function Person (name,age){this.name = name;this.age = age;this.habit = 'Games';
}
Person.prototype.strength = 80;
Person.prototype.sayYourName = function (){console.log('I am ', this.name);
}
var person = new Person('kin',18);
console.log(person.name);//kin
console.log(person.habit);//Games
console.log(person.strength);//80
person.sayYourName();// I am kin
我們可以看到,實例person可以:
- 訪問到Otaku構造函數里的屬性;
- 訪問到Otaku.prototype中的屬性;
接下來,我們可以嘗試著模擬一下:
因為new是關鍵字,所以無法像bind函數一樣直接覆蓋,所以我們寫一個函數,命名為objectFactory,來模擬new的效果,用的時候是這樣的:
function Person(){...
}
//使用new
var person = new Person(...);
//使用objectFactory
var person = objectFactory(Person,...)
初步實現
因為new的結果是一個新的對象,所以在模擬實現的時候,我們也要建立一個新對象,假設這個對象叫obj,因為obj會具有Person構造函數里的屬性,我們可以使用
Person.apply(obj,arguments)
來給obj添加新的屬性。
然后,實例的proto
屬性會指向構造函數的prototype
,也正是因為建立起這樣的關系,實例可以訪問原型上的屬性。
//第一版代碼
function objectFactory(){var obj = new Object();Constructor = [].shift.call(arguments);obj.__proto__ = Constructor.prototype;Constructor.apply(obj,arguments);return obj;
}
在這一版中,我們:
- 用new Object()的方式新建了一個對象obj;
- 取出第一個參數,就是我們要傳入的構造函數。此外因為shift會修改原數組,所以arguments會被去除第一個參數;
- 將obj的原型指向構造函數,這樣obj就可以訪問到構造函數原型中的屬性;
- 使用apply,改變構造函數this的指向到新建的對象,這樣obj就可以訪問到構造函數中的屬性;
- 返回obj;
測試下:
function Person (name,age){this.name = name;this,age = age;this,habit = 'Games';
}
Person.prototype.strength = 88;
Person.prototype.sayYourName = function(){console.log('I am',this.name);
}
function objectFactory(){var obj = new Object();Constructor = [].shift.call(arguments);obj.__proto__ = Constructor.prototype;Constructor.apply(obj,arguments);return obj;
};
var person = objectFactory(Person,'kin',17);
console.log(person.name);//kin
console.log(person.habit);//Games
console.log(person.strength);//88
person.sayYourName();// I am kin
最終實現
假如構造函數有返回值
function Person(name,age){this.strength = 90;this.age = age;return {name:name,habit:'Games'}
}
var person = new Person('kin',12);
console.log(person.name);//kin
console.log(person.habit);//Games
console.log(person.strength);//undefined
console.log(person.age);//undefined
在這個案例中,構造函數返回了一個對象,在實例person中只能訪問返回的對象中的屬性。
而且還要注意一點,在這里我們是返回一個對象,假如我們只是返回一個基本類型的值呢?
我們再看一個例子:
Function Person(name,age){this.strength = 60;this.age = age;return 'handsome boy';
}
var person = new Otaku('kin',12);
console.log(person.name);//undefined
console.log(person.age);//undefined
console.log(person.strength);//60
console.log(person.age);//18
這次盡管有返回值,但是相當于沒有對返回值進行處理。
所以我們還需要判斷返回的值是不是一個對象,如果是一個對象,我們就返回這個對象,如果沒有,我們該返回什么就返回什么。
//最終版的代碼
function objectFactory(){var obj = new Object();Constructor = [].shift.call(arguments);obj.__proto__ = Constructor.apply(obj,arguments);return typeof ret == 'object' ? ret : obj;
};
本文章可以參考JS基礎之原型&原型鏈一起看,學習效果更佳喲~
好啦!簡單的知識點就到這里啦休息一下獎勵自己一下!