new 運算符建立一個用戶定義的對象類型的實例或具備構造函數的內置對象的實例。 ——(來自於MDN)
舉個栗子javascript
function Car(color) { this.color = color; } Car.prototype.start = function() { console.log(this.color + " car start"); } var car = new Car("black"); car.color; // 訪問構造函數裏的屬性 // black car.start(); // 訪問原型裏的屬性 // black car start
能夠看出 new
建立的實例有如下 2 個特性html
ES6新增 symbol
類型,不可使用 new Symbol()
,由於 symbol
是基本數據類型,每一個從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
當代碼 new Foo(...)
執行時,會發生如下事情:java
Foo.prototype
的新對象被建立。Foo
,並將 this
綁定到新建立的對象。new Foo
等同於 new Foo()
,也就是沒有指定參數列表,Foo
不帶任何參數調用的狀況。new
表達式的結果。若是構造函數沒有顯式返回一個對象,則使用步驟1建立的對象。new
是關鍵詞,不能夠直接覆蓋。這裏使用 create
來模擬實現 new
的效果。webpack
new
返回一個新對象,經過 obj.__proto__ = Con.prototype
繼承構造函數的原型,同時經過 Con.apply(obj, arguments)
調用父構造函數實現繼承,獲取構造函數上的屬性(【進階3-3期】)。git
實現代碼以下github
// 初版 function create() { // 建立一個空的對象 var obj = new Object(), // 得到構造函數,arguments中去除第一個參數 Con = [].shift.call(arguments); // 連接到原型,obj 能夠訪問到構造函數原型中的屬性 obj.__proto__ = Con.prototype; // 綁定 this 實現繼承,obj 能夠訪問到構造函數中的屬性 Con.apply(obj, arguments); // 返回對象 return obj; };
測試一下web
// 測試用例 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 原理、使用場景及實現算法
不熟悉繼承的點擊查看:JavaScript經常使用八種繼承方案
上面的代碼已經實現了 80%,如今繼續優化。
構造函數返回值有以下三種狀況:
return
,即返回 undefined
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
中只能訪問到構造函數中的屬性,和狀況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
中只能訪問到構造函數中的屬性,和狀況1徹底相反,結果至關於沒有返回值。
因此須要判斷下返回的值是否是一個對象,若是是對象則返回這個對象,否則返回新建立的 obj
對象。
因此實現代碼以下:
// 第二版 function create() { // 建立一個空的對象 var obj = new Object(), // 得到構造函數,arguments中去除第一個參數 Con = [].shift.call(arguments); // 連接到原型,obj 能夠訪問到構造函數原型中的屬性 obj.__proto__ = Con.prototype; // 綁定 this 實現繼承,obj 能夠訪問到構造函數中的屬性 var ret = Con.apply(obj, arguments); // 優先返回構造函數返回的對象 return ret instanceof Object ? ret : obj; };
問題:用 JS 實現一個無限累加的函數 add
,示例以下:
add(1); // 1 add(1)(2); // 3 add(1)(2)(3); // 6 add(1)(2)(3)(4); // 10 // 以此類推
實現:
function add(a) { function sum(b) { // 使用閉包 a = a + b; // 累加 return sum; } sum.toString = function() { // 重寫toString()方法 return a; } return sum; // 返回一個函數 } add(1); // 1 add(1)(2); // 3 add(1)(2)(3); // 6 add(1)(2)(3)(4); // 10
咱們知道打印函數時會自動調用 toString()
方法,函數 add(a)
返回一個閉包 sum(b)
,函數 sum()
中累加計算 a = a + b
,只須要重寫sum.toString()
方法返回變量 a
就OK了。
JavaScript 深刻之 new 的模擬實現
進階系列文章彙總以下,內有優質前端資料,以爲不錯點個star。
https://github.com/yygmind/blog
我是木易楊,網易高級前端工程師,跟着我每週重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!