new
一句話介紹 new:
new 運(yùn)算符創(chuàng)建一個(gè)用戶(hù)定義的對(duì)象類(lèi)型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象類(lèi)型之一
也許有點(diǎn)難懂,我們?cè)谀M new 之前,先看看 new 實(shí)現(xiàn)了哪些功能。
舉個(gè)例子:
// Muku 御宅族,簡(jiǎn)稱(chēng)宅
function Muku (name, age) {
this.name = name;
this.age = age;
this.habit = 'Games';
}
// 因?yàn)槿狈﹀憻挼木壒?,身體強(qiáng)度讓人擔(dān)憂
Muku.prototype.strength = 60;
Muku.prototype.sayYourName = function () {
console.log('I am ' + this.name);
}
var person = new Muku('Kevin', '18');
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
person.sayYourName(); // I am Kevin復(fù)制代碼
從這個(gè)例子中,我們可以看到,實(shí)例 person 可以:
- 訪問(wèn)到 Muku 構(gòu)造函數(shù)里的屬性
- 訪問(wèn)到 Muku.prototype 中的屬性
接下來(lái),我們可以嘗試著模擬一下了。
因?yàn)?new 是關(guān)鍵字,所以無(wú)法像 bind 函數(shù)一樣直接覆蓋,所以我們寫(xiě)一個(gè)函數(shù),命名為 objectFactory,來(lái)模擬 new 的效果。用的時(shí)候是這樣的:
function Muku () {
……
}
// 使用 new
var person = new Muku(……);
// 使用 objectFactory
var person = objectFactory(Muku, ……)復(fù)制代碼
初步實(shí)現(xiàn)
分析:
因?yàn)?new 的結(jié)果是一個(gè)新對(duì)象,所以在模擬實(shí)現(xiàn)的時(shí)候,我們也要建立一個(gè)新對(duì)象,假設(shè)這個(gè)對(duì)象叫 obj,因?yàn)?obj 會(huì)具有Muku 構(gòu)造函數(shù)里的屬性,想想經(jīng)典繼承的例子,我們可以使用 Muku.apply(obj, arguments)來(lái)給 obj 添加新的屬性。
我們知道實(shí)例的 proto 屬性會(huì)指向構(gòu)造函數(shù)的 prototype,也正是因?yàn)榻⑵疬@樣的關(guān)系,實(shí)例可以訪問(wèn)原型上的屬性。
現(xiàn)在,我們可以嘗試著寫(xiě)第一版了:
// 第一版代碼
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
Constructor.apply(obj, arguments);
return obj;
};復(fù)制代碼
在這一版中,我們:
- 用
new Object()的方式新建了一個(gè)對(duì)象obj - 取出第一個(gè)參數(shù),就是我們要傳入的構(gòu)造函數(shù)。此外因?yàn)?
shift會(huì)修改原數(shù)組,所以arguments會(huì)被去除第一個(gè)參數(shù) - 將
obj的原型指向構(gòu)造函數(shù),這樣obj就可以訪問(wèn)到構(gòu)造函數(shù)原型中的屬性 - 使用
apply,改變構(gòu)造函數(shù)this的指向到新建的對(duì)象,這樣obj就可以訪問(wèn)到構(gòu)造函數(shù)中的屬性 - 返回
obj
function Muku (name, age) {
this.name = name;
this.age = age;
this.habit = 'Games';
}
Muku.prototype.strength = 60;
Muku.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(Muku, 'Kevin', '18')
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
person.sayYourName(); // I am Kevin復(fù)制代碼
返回值效果實(shí)現(xiàn)
接下來(lái)我們?cè)賮?lái)看一種情況,假如構(gòu)造函數(shù)有返回值,舉個(gè)例子:
function Otaku (name, age) {
this.strength = 60;
this.age = age;
return {
name: name,
habit: 'Games'
}
}
var person = new Otaku('Kevin', '18');
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // undefined
console.log(person.age) // undefined復(fù)制代碼
在這個(gè)例子中,構(gòu)造函數(shù)返回了一個(gè)對(duì)象,在實(shí)例 person 中只能訪問(wèn)返回的對(duì)象中的屬性。
而且還要注意一點(diǎn),在這里我們是返回了一個(gè)對(duì)象,假如我們只是返回一個(gè)基本類(lèi)型的值呢?
再舉個(gè)例子:
function Otaku (name, age) {
this.strength = 60;
this.age = age;
return 'handsome boy';
}
var person = new Otaku('Kevin', '18');
console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.strength) // 60
console.log(person.age) // 18復(fù)制代碼
結(jié)果完全顛倒過(guò)來(lái),這次盡管有返回值,但是相當(dāng)于沒(méi)有返回值進(jìn)行處理。
所以我們還需要判斷返回的值是不是一個(gè)對(duì)象,如果是一個(gè)對(duì)象,我們就返回這個(gè)對(duì)象,如果沒(méi)有,我們?cè)摲祷厥裁淳头祷厥裁础?/p>
再來(lái)看第二版的代碼,也是最后一版的代碼:
// 第二版的代碼
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret : obj;
};