摘要:使用指定的參數調用構造函數,并將綁定到新創建的對象。由構造函數返回的對象就是表達式的結果。情況返回以外的基本類型實例中只能訪問到構造函數中的屬性,和情況完全相反,結果相當于沒有返回值。
定義
new 運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象的實例。 ——(來自于MDN)
舉個栗子
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 個特性
1、訪問到構造函數里的屬性
2、訪問到原型里的屬性
注意點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(...) 執行時,會發生以下事情:
一個繼承自 Foo.prototype 的新對象被創建。
使用指定的參數調用構造函數 Foo ,并將 this 綁定到新創建的對象。new Foo 等同于 new Foo(),也就是沒有指定參數列表,Foo 不帶任何參數調用的情況。
由構造函數返回的對象就是 new 表達式的結果。如果構造函數沒有顯式返回一個對象,則使用步驟1創建的對象。
模擬實現第一步new 是關鍵詞,不可以直接覆蓋。這里使用 create 來模擬實現 new 的效果。
new 返回一個新對象,通過 obj.__proto__ = Con.prototype 繼承構造函數的原型,同時通過 Con.apply(obj, arguments)調用父構造函數實現繼承,獲取構造函數上的屬性(【進階3-3期】)。
實現代碼如下
// 第一版 function create() { // 創建一個空的對象 var obj = new Object(), // 獲得構造函數,arguments中去除第一個參數 Con = [].shift.call(arguments); // 鏈接到原型,obj 可以訪問到構造函數原型中的屬性 obj.__proto__ = Con.prototype; // 綁定 this 實現繼承,obj 可以訪問到構造函數中的屬性 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 原理、使用場景及實現
不熟悉繼承的點擊查看:JavaScript常用八種繼承方案
模擬實現第二步上面的代碼已經實現了 80%,現在繼續優化。
構造函數返回值有如下三種情況:
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 中只能訪問到構造函數中的屬性,和情況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; };【進階3-4期】思考題解
問題:用 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 的模擬實現進階系列目錄MDN 之 new 運算符
MDN 之 Symbol
javascript 函數 add(1)(2)(3)(4) 實現無限極累加
【進階1期】 調用堆棧
【進階2期】 作用域閉包
【進階3期】 this全面解析
【進階4期】 深淺拷貝原理
【進階5期】 原型Prototype
【進階6期】 高階函數
【進階7期】 事件機制
【進階8期】 Event Loop原理
【進階9期】 Promise原理
【進階10期】Async/Await原理
【進階11期】防抖/節流原理
【進階12期】模塊化詳解
【進階13期】ES6重難點
【進階14期】計算機網絡概述
【進階15期】瀏覽器渲染原理
【進階16期】webpack配置
【進階17期】webpack原理
【進階18期】前端監控
【進階19期】跨域和安全
【進階20期】性能優化
【進階21期】VirtualDom原理
【進階22期】Diff算法
【進階23期】MVVM雙向綁定
【進階24期】Vuex原理
【進階25期】Redux原理
【進階26期】路由原理
【進階27期】VueRouter源碼解析
【進階28期】ReactRouter源碼解析
交流進階系列文章匯總如下,內有優質前端資料,覺得不錯點個star。
https://github.com/yygmind/blog
我是木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100734.html
摘要:返回的綁定函數也能使用操作符創建對象這種行為就像把原函數當成構造器,提供的值被忽略,同時調用時的參數被提供給模擬函數。 bind() bind() 方法會創建一個新函數,當這個新函數被調用時,它的 this 值是傳遞給 bind() 的第一個參數,傳入bind方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。bind返回的綁定函數也能使用 n...
摘要:之前文章詳細介紹了的使用,不了解的查看進階期。不同的引擎有不同的限制,核心限制在,有些引擎會拋出異常,有些不拋出異常但丟失多余參數。存儲的對象能動態增多和減少,并且可以存儲任何值。這邊采用方法來實現,拼成一個函數。 之前文章詳細介紹了 this 的使用,不了解的查看【進階3-1期】。 call() 和 apply() call() 方法調用一個函數, 其具有一個指定的 this 值和分...
摘要:本期推薦文章類內存泄漏及如何避免,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。四種常見的內存泄漏劃重點這是個考點意外的全局變量未定義的變量會在全局對象創建一個新變量,如下。因為老版本的是無法檢測節點與代碼之間的循環引用,會導致內存泄漏。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題...
摘要:木易楊注意原始類型被包裝為對象木易楊原始類型會被包裝,和會被忽略。木易楊原因在于時,其屬性描述符為不可寫,即。木易楊解決方法也很簡單,使用我們在進階期中介紹的就可以了,使用如下。 引言 上篇文章介紹了賦值、淺拷貝和深拷貝,其中介紹了很多賦值和淺拷貝的相關知識以及兩者區別,限于篇幅只介紹了一種常用深拷貝方案。 本篇文章會先介紹淺拷貝 Object.assign 的實現原理,然后帶你手動實...
摘要:今天這篇文章我們來看看一道必會面試題,即如何實現一個深拷貝。木易楊注意這里使用上面測試用例測試一下一個簡單的深拷貝就完成了,但是這個實現還存在很多問題。 引言 上篇文章詳細介紹了淺拷貝 Object.assign,并對其進行了模擬實現,在實現的過程中,介紹了很多基礎知識。今天這篇文章我們來看看一道必會面試題,即如何實現一個深拷貝。本文會詳細介紹對象、數組、循環引用、引用丟失、Symbo...
閱讀 649·2021-11-25 09:43
閱讀 1668·2021-11-18 10:02
閱讀 1041·2021-10-15 09:39
閱讀 1890·2021-10-12 10:18
閱讀 2122·2021-09-22 15:43
閱讀 773·2021-09-22 15:10
閱讀 2088·2019-08-30 15:53
閱讀 988·2019-08-30 13:00