定義
new 運(yùn)算符創(chuàng)建一個(gè)用戶(hù)定義的對(duì)象類(lèi)型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。 ——(來(lái)自于MDN)
舉個(gè)栗子
function Car(color) {
this.color = color;
}
Car.prototype.start = function() {
console.log(this.color + " car start");
}
var car = new Car("black");
car.color; // 訪(fǎng)問(wèn)構(gòu)造函數(shù)里的屬性
// black
car.start(); // 訪(fǎng)問(wèn)原型里的屬性
// black car start
可以看出 new 創(chuàng)建的實(shí)例有以下 2 個(gè)特性
- 訪(fǎng)問(wèn)到構(gòu)造函數(shù)里的屬性
- 訪(fǎng)問(wèn)到原型里的屬性
注意點(diǎn)
ES6新增 symbol 類(lèi)型有勾,不可以使用 new Symbol(),因?yàn)?symbol 是基本數(shù)據(jù)類(lèi)型蛙吏,每個(gè)從Symbol()返回的 symbol 值都是唯一的涉瘾。
Number("123"); // 123
String(123); // "123"
Boolean(123); // true
Symbol(123); // Symbol(123)
new Number("123"); // Number {123}
new String(123); // String {"123"}
new Boolean(true); // Boolean {true}
new Symbol(123); // Symbol is not a constructor
模擬實(shí)現(xiàn)
當(dāng)代碼 new Foo(...) 執(zhí)行時(shí)要出,會(huì)發(fā)生以下事情:
- 一個(gè)繼承自 Foo.prototype 的新對(duì)象被創(chuàng)建捉偏。
- 使用指定的參數(shù)調(diào)用構(gòu)造函數(shù) Foo 倒得,并將 this 綁定到新創(chuàng)建的對(duì)象。new Foo 等同于 new Foo()夭禽,也就是沒(méi)有指定參數(shù)列表霞掺,F(xiàn)oo 不帶任何參數(shù)調(diào)用的情況。
- 由構(gòu)造函數(shù)返回的對(duì)象就是 new 表達(dá)式的結(jié)果讹躯。如果構(gòu)造函數(shù)沒(méi)有顯式返回一個(gè)對(duì)象菩彬,則使用步驟1創(chuàng)建的對(duì)象。
模擬實(shí)現(xiàn)第一步
new 是關(guān)鍵詞潮梯,不可以直接覆蓋挤巡。這里使用 create 來(lái)模擬實(shí)現(xiàn) new 的效果。
new 返回一個(gè)新對(duì)象酷麦,通過(guò) obj.proto = Con.prototype 繼承構(gòu)造函數(shù)的原型,同時(shí)通過(guò) Con.apply(obj, arguments)調(diào)用父構(gòu)造函數(shù)實(shí)現(xiàn)繼承喉恋,獲取構(gòu)造函數(shù)上的屬性(【進(jìn)階3-3期】)沃饶。實(shí)現(xiàn)代碼如下
// 第一版
function create() {
// 創(chuàng)建一個(gè)空的對(duì)象
var obj = new Object(),
// 獲得構(gòu)造函數(shù),arguments中去除第一個(gè)參數(shù)
Con = [].shift.call(arguments);
// 鏈接到原型轻黑,obj 可以訪(fǎng)問(wèn)到構(gòu)造函數(shù)原型中的屬性
obj.__proto__ = Con.prototype;
// 綁定 this 實(shí)現(xiàn)繼承糊肤,obj 可以訪(fǎng)問(wèn)到構(gòu)造函數(shù)中的屬性
Con.apply(obj, arguments);
// 返回對(duì)象
return obj;
};
測(cè)試一下
// 測(cè)試用例
function Car(color) {
this.color = color;
}
Car.prototype.start = function() {
console.log(this.color + " car start");
}
var car = create(Car, "black");
car.color;
// black
car.start();
// black car start
完美!不熟悉 apply / call 的搜索查看:深度解析 call 和 apply 原理氓鄙、使用場(chǎng)景及實(shí)現(xiàn)馆揉。不熟悉繼承的查看:JavaScript常用八種繼承方案
模擬實(shí)現(xiàn)第二步
上面的代碼已經(jīng)實(shí)現(xiàn)了 80%,現(xiàn)在繼續(xù)優(yōu)化抖拦。構(gòu)造函數(shù)返回值有如下三種情況:
- 返回一個(gè)對(duì)象
- 沒(méi)有 return升酣,即返回 undefined
- 返回undefined 以外的基本類(lèi)型
情況1:返回一個(gè)對(duì)象
function Car(color, name) {
this.color = color;
return {
name: name
}
}
var car = new Car("black", "BMW");
car.color;
// undefined
car.name;
// "BMW"
實(shí)例 car 中只能訪(fǎng)問(wèn)到返回對(duì)象中的屬性。
情況2:沒(méi)有 return态罪,即返回 undefined
function Car(color, name) {
this.color = color;
}
var car = new Car("black", "BMW");
car.color;
// black
car.name;
// undefined
實(shí)例 car 中只能訪(fǎng)問(wèn)到構(gòu)造函數(shù)中的屬性噩茄,和情況1完全相反。
情況3:返回undefined 以外的基本類(lèi)型
function Car(color, name) {
this.color = color;
return "new car";
}
var car = new Car("black", "BMW");
car.color;
// black
car.name;
// undefined
實(shí)例 car 中只能訪(fǎng)問(wèn)到構(gòu)造函數(shù)中的屬性复颈,和情況1完全相反绩聘,結(jié)果相當(dāng)于沒(méi)有返回值。
所以需要判斷下返回的值是不是一個(gè)對(duì)象,如果是對(duì)象則返回這個(gè)對(duì)象凿菩,不然返回新創(chuàng)建的 obj對(duì)象机杜。所以實(shí)現(xiàn)代碼如下:
// 第二版
function create() {
// 創(chuàng)建一個(gè)空的對(duì)象
var obj = new Object(),
// 獲得構(gòu)造函數(shù),arguments中去除第一個(gè)參數(shù)
Con = [].shift.call(arguments);
// 鏈接到原型衅谷,obj 可以訪(fǎng)問(wèn)到構(gòu)造函數(shù)原型中的屬性
obj.__proto__ = Con.prototype;
// 綁定 this 實(shí)現(xiàn)繼承椒拗,obj 可以訪(fǎng)問(wèn)到構(gòu)造函數(shù)中的屬性
var ret = Con.apply(obj, arguments);
// 優(yōu)先返回構(gòu)造函數(shù)返回的對(duì)象
return typeof ret === 'object' ? ret : obj;
};
思考題
問(wèn)題:用 JS 實(shí)現(xiàn)一個(gè)無(wú)限累加的函數(shù) add,示例如下:
add(1); // 1
add(1)(2); // 3
add(1)(2)(3)会喝; // 6
add(1)(2)(3)(4)陡叠; // 10
// 以此類(lèi)推
實(shí)現(xiàn):
function add(a) {
function sum(b) { // 使用閉包
a = a + b; // 累加
return sum;
}
sum.toString = function() { // 重寫(xiě)toString()方法
return a;
}
return sum; // 返回一個(gè)函數(shù)
}
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4)肢执; // 10
我們知道打印函數(shù)時(shí)會(huì)自動(dòng)調(diào)用 toString()方法枉阵,函數(shù) add(a) 返回一個(gè)閉包 sum(b),函數(shù) sum() 中累加計(jì)算 a = a + b预茄,只需要重寫(xiě)sum.toString()方法返回變量 a 就OK了兴溜。
參考
看完文章,還有福利拿耻陕,往下看??????
感興趣的小伙伴可以在公號(hào)【grain先森】后臺(tái)回復(fù)【190313】獲取HTML5詳解拙徽、CSS3詳解和Vue詳解及實(shí)戰(zhàn)項(xiàng)目,可以轉(zhuǎn)發(fā)朋友圈和你的朋友分享哦诗宣。