定義
new 運算符創(chuàng)建一個用戶定義的對象類型的實例或具有構造函數(shù)的內置對象的實例。 ——(來自于MDN)
舉個栗子
function Car(color) {
this.color = color;
}
Car.prototype.start = function() {
console.log(this.color + " car start");
}
var car = new Car("black");
car.color; // 訪問構造函數(shù)里的屬性
// black
car.start(); // 訪問原型里的屬性
// black car start
可以看出 new 創(chuàng)建的實例有以下 2 個特性
- 1、訪問到構造函數(shù)里的屬性
- 2、訪問到原型里的屬性
注意點
ES6新增 symbol 類型,不可以使用 new Symbol(),因為 symbol 是基本數(shù)據(jù)類型,每個從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
模擬實現(xiàn)
當代碼 new Foo(...) 執(zhí)行時,會發(fā)生以下事情:
- 一個繼承自
Foo.prototype的新對象被創(chuàng)建。 - 使用指定的參數(shù)調用構造函數(shù)
Foo,并將this綁定到新創(chuàng)建的對象。new Foo等同于new Foo(),也就是沒有指定參數(shù)列表,Foo不帶任何參數(shù)調用的情況。 - 由構造函數(shù)返回的對象就是
new表達式的結果。如果構造函數(shù)沒有顯式返回一個對象,則使用步驟1創(chuàng)建的對象。
模擬實現(xiàn)第一步
new 是關鍵詞,不可以直接覆蓋。這里使用 create 來模擬實現(xiàn) new 的效果。
new 返回一個新對象,通過 obj.__proto__ = Con.prototype 繼承構造函數(shù)的原型,同時通過 Con.apply(obj, arguments)調用父構造函數(shù)實現(xiàn)繼承,獲取構造函數(shù)上的屬性(【進階3-3期】)。
實現(xiàn)代碼如下
// 第一版
function create() {
// 創(chuàng)建一個空的對象
var obj = new Object(),
// 獲得構造函數(shù),arguments中去除第一個參數(shù)
Con = [].shift.call(arguments);
// 鏈接到原型,obj 可以訪問到構造函數(shù)原型中的屬性
obj.__proto__ = Con.prototype;
// 綁定 this 實現(xiàn)繼承,obj 可以訪問到構造函數(shù)中的屬性
Con.apply(obj, arguments);
// 返回對象
return obj;
};
測試一下
// 測試用例
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 的點擊查看:【進階3-3期】深度解析 call 和 apply 原理、使用場景及實現(xiàn)
不熟悉繼承的點擊查看:JavaScript常用八種繼承方案
模擬實現(xiàn)第二步
上面的代碼已經實現(xiàn)了 80%,現(xiàn)在繼續(xù)優(yōu)化。
構造函數(shù)返回值有如下三種情況:
- 1、返回一個對象
- 2、沒有
return,即返回undefined - 3、返回
undefined以外的基本類型
情況1:返回一個對象
function Car(color, name) {
this.color = color;
return {
name: name
}
}
var car = new Car("black", "BMW");
car.color;
// undefined
car.name;
// "BMW"
實例 car 中只能訪問到返回對象中的屬性。
情況2:沒有 return,即返回 undefined
function Car(color, name) {
this.color = color;
}
var car = new Car("black", "BMW");
car.color;
// black
car.name;
// undefined
實例 car 中只能訪問到構造函數(shù)中的屬性,和情況1完全相反。
情況3:返回undefined 以外的基本類型
function Car(color, name) {
this.color = color;
return "new car";
}
var car = new Car("black", "BMW");
car.color;
// black
car.name;
// undefined
實例 car 中只能訪問到構造函數(shù)中的屬性,和情況1完全相反,結果相當于沒有返回值。
所以需要判斷下返回的值是不是一個對象,如果是對象則返回這個對象,不然返回新創(chuàng)建的 obj對象。
所以實現(xiàn)代碼如下:
// 第二版
function create() {
// 創(chuàng)建一個空的對象
var obj = new Object(),
// 獲得構造函數(shù),arguments中去除第一個參數(shù)
Con = [].shift.call(arguments);
// 鏈接到原型,obj 可以訪問到構造函數(shù)原型中的屬性
obj.__proto__ = Con.prototype;
// 綁定 this 實現(xiàn)繼承,obj 可以訪問到構造函數(shù)中的屬性
var ret = Con.apply(obj, arguments);
// 優(yōu)先返回構造函數(shù)返回的對象
return ret instanceof Object ? ret : obj;
};
【進階3-4期】思考題解
問題:用 JS 實現(xiàn)一個無限累加的函數(shù) add,示例如下:
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10
// 以此類推
實現(xiàn):
function add(a) {
function sum(b) { // 使用閉包
a = a + b; // 累加
return sum;
}
sum.toString = function() { // 重寫toString()方法
return a;
}
return sum; // 返回一個函數(shù)
}
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10
我們知道打印函數(shù)時會自動調用 toString()方法,函數(shù) add(a) 返回一個閉包 sum(b),函數(shù) sum() 中累加計算 a = a + b,只需要重寫sum.toString()方法返回變量 a 就OK了。
參考
進階系列目錄
- 【進階1期】 調用堆棧
- 【進階2期】 作用域閉包
- 【進階3期】 this全面解析
- 【進階4期】 深淺拷貝原理
- 【進階5期】 原型Prototype
- 【進階6期】 高階函數(shù)
- 【進階7期】 事件機制
- 【進階8期】 Event Loop原理
- 【進階9期】 Promise原理
- 【進階10期】Async/Await原理
- 【進階11期】防抖/節(jié)流原理
- 【進階12期】模塊化詳解
- 【進階13期】ES6重難點
- 【進階14期】計算機網絡概述
- 【進階15期】瀏覽器渲染原理
- 【進階16期】webpack配置
- 【進階17期】webpack原理
- 【進階18期】前端監(jiān)控
- 【進階19期】跨域和安全
- 【進階20期】性能優(yōu)化
- 【進階21期】VirtualDom原理
- 【進階22期】Diff算法
- 【進階23期】MVVM雙向綁定
- 【進階24期】Vuex原理
- 【進階25期】Redux原理
- 【進階26期】路由原理
- 【進階27期】VueRouter源碼解析
- 【進階28期】ReactRouter源碼解析
交流
進階系列文章匯總如下,內有優(yōu)質前端資料,覺得不錯點個star。
我是木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。接下來讓我?guī)阕哌M高級前端的世界,在進階的路上,共勉!
