摘要:使用指定的參數(shù)調(diào)用構(gòu)造函數(shù),并將綁定到新創(chuàng)建的對(duì)象。由構(gòu)造函數(shù)返回的對(duì)象就是表達(dá)式的結(jié)果。情況返回以外的基本類型實(shí)例中只能訪問(wèn)到構(gòu)造函數(shù)中的屬性,和情況完全相反,結(jié)果相當(dāng)于沒(méi)有返回值。
定義
new 運(yùn)算符創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(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; // 訪問(wèn)構(gòu)造函數(shù)里的屬性 // black car.start(); // 訪問(wèn)原型里的屬性 // black car start
可以看出 new 創(chuàng)建的實(shí)例有以下 2 個(gè)特性
1、訪問(wèn)到構(gòu)造函數(shù)里的屬性
2、訪問(wèn)到原型里的屬性
注意點(diǎn)ES6新增 symbol 類型,不可以使用 new Symbol(),因?yàn)?symbol 是基本數(shù)據(jù)類型,每個(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ù)列表,Foo 不帶任何參數(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 可以訪問(wèn)到構(gòu)造函數(shù)原型中的屬性 obj.__proto__ = Con.prototype; // 綁定 this 實(shí)現(xiàn)繼承,obj 可以訪問(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 的點(diǎn)擊查看:【進(jìn)階3-3期】深度解析 call 和 apply 原理、使用場(chǎng)景及實(shí)現(xiàn)
不熟悉繼承的點(diǎn)擊查看:JavaScript常用八種繼承方案
模擬實(shí)現(xiàn)第二步上面的代碼已經(jīng)實(shí)現(xiàn)了 80%,現(xiàn)在繼續(xù)優(yōu)化。
構(gòu)造函數(shù)返回值有如下三種情況:
1、返回一個(gè)對(duì)象
2、沒(méi)有 return,即返回 undefined
3、返回undefined 以外的基本類型
情況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 中只能訪問(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 中只能訪問(wèn)到構(gòu)造函數(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
實(shí)例 car 中只能訪問(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 可以訪問(wèn)到構(gòu)造函數(shù)原型中的屬性 obj.__proto__ = Con.prototype; // 綁定 this 實(shí)現(xiàn)繼承,obj 可以訪問(wèn)到構(gòu)造函數(shù)中的屬性 var ret = Con.apply(obj, arguments); // 優(yōu)先返回構(gòu)造函數(shù)返回的對(duì)象 return ret instanceof Object ? ret : obj; };【進(jìn)階3-4期】思考題解
問(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 // 以此類推
實(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了。
參考JavaScript 深入之 new 的模擬實(shí)現(xiàn)進(jìn)階系列目錄MDN 之 new 運(yùn)算符
MDN 之 Symbol
javascript 函數(shù) add(1)(2)(3)(4) 實(shí)現(xiàn)無(wú)限極累加
【進(jìn)階1期】 調(diào)用堆棧
【進(jìn)階2期】 作用域閉包
【進(jìn)階3期】 this全面解析
【進(jìn)階4期】 深淺拷貝原理
【進(jìn)階5期】 原型Prototype
【進(jìn)階6期】 高階函數(shù)
【進(jìn)階7期】 事件機(jī)制
【進(jìn)階8期】 Event Loop原理
【進(jìn)階9期】 Promise原理
【進(jìn)階10期】Async/Await原理
【進(jìn)階11期】防抖/節(jié)流原理
【進(jìn)階12期】模塊化詳解
【進(jìn)階13期】ES6重難點(diǎn)
【進(jìn)階14期】計(jì)算機(jī)網(wǎng)絡(luò)概述
【進(jìn)階15期】瀏覽器渲染原理
【進(jìn)階16期】webpack配置
【進(jìn)階17期】webpack原理
【進(jìn)階18期】前端監(jiān)控
【進(jìn)階19期】跨域和安全
【進(jìn)階20期】性能優(yōu)化
【進(jìn)階21期】VirtualDom原理
【進(jìn)階22期】Diff算法
【進(jìn)階23期】MVVM雙向綁定
【進(jìn)階24期】Vuex原理
【進(jìn)階25期】Redux原理
【進(jìn)階26期】路由原理
【進(jìn)階27期】VueRouter源碼解析
【進(jìn)階28期】ReactRouter源碼解析
交流進(jìn)階系列文章匯總?cè)缦拢瑑?nèi)有優(yōu)質(zhì)前端資料,覺(jué)得不錯(cuò)點(diǎn)個(gè)star。
https://github.com/yygmind/blog
我是木易楊,網(wǎng)易高級(jí)前端工程師,跟著我每周重點(diǎn)攻克一個(gè)前端面試重難點(diǎn)。接下來(lái)讓我?guī)阕哌M(jìn)高級(jí)前端的世界,在進(jìn)階的路上,共勉!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/100734.html
摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對(duì)象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器,提供的值被忽略,同時(shí)調(diào)用時(shí)的參數(shù)被提供給模擬函數(shù)。 bind() bind() 方法會(huì)創(chuàng)建一個(gè)新函數(shù),當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí),它的 this 值是傳遞給 bind() 的第一個(gè)參數(shù),傳入bind方法的第二個(gè)以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時(shí)本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來(lái)調(diào)用原函數(shù)。bind返回的綁定函數(shù)也能使用 n...
摘要:之前文章詳細(xì)介紹了的使用,不了解的查看進(jìn)階期。不同的引擎有不同的限制,核心限制在,有些引擎會(huì)拋出異常,有些不拋出異常但丟失多余參數(shù)。存儲(chǔ)的對(duì)象能動(dòng)態(tài)增多和減少,并且可以存儲(chǔ)任何值。這邊采用方法來(lái)實(shí)現(xiàn),拼成一個(gè)函數(shù)。 之前文章詳細(xì)介紹了 this 的使用,不了解的查看【進(jìn)階3-1期】。 call() 和 apply() call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的 this 值和分...
摘要:本期推薦文章類內(nèi)存泄漏及如何避免,由于微信不能訪問(wèn)外鏈,點(diǎn)擊閱讀原文就可以啦。四種常見(jiàn)的內(nèi)存泄漏劃重點(diǎn)這是個(gè)考點(diǎn)意外的全局變量未定義的變量會(huì)在全局對(duì)象創(chuàng)建一個(gè)新變量,如下。因?yàn)槔习姹镜氖菬o(wú)法檢測(cè)節(jié)點(diǎn)與代碼之間的循環(huán)引用,會(huì)導(dǎo)致內(nèi)存泄漏。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第一期,本周的主題...
摘要:木易楊注意原始類型被包裝為對(duì)象木易楊原始類型會(huì)被包裝,和會(huì)被忽略。木易楊原因在于時(shí),其屬性描述符為不可寫(xiě),即。木易楊解決方法也很簡(jiǎn)單,使用我們?cè)谶M(jìn)階期中介紹的就可以了,使用如下。 引言 上篇文章介紹了賦值、淺拷貝和深拷貝,其中介紹了很多賦值和淺拷貝的相關(guān)知識(shí)以及兩者區(qū)別,限于篇幅只介紹了一種常用深拷貝方案。 本篇文章會(huì)先介紹淺拷貝 Object.assign 的實(shí)現(xiàn)原理,然后帶你手動(dòng)實(shí)...
摘要:今天這篇文章我們來(lái)看看一道必會(huì)面試題,即如何實(shí)現(xiàn)一個(gè)深拷貝。木易楊注意這里使用上面測(cè)試用例測(cè)試一下一個(gè)簡(jiǎn)單的深拷貝就完成了,但是這個(gè)實(shí)現(xiàn)還存在很多問(wèn)題。 引言 上篇文章詳細(xì)介紹了淺拷貝 Object.assign,并對(duì)其進(jìn)行了模擬實(shí)現(xiàn),在實(shí)現(xiàn)的過(guò)程中,介紹了很多基礎(chǔ)知識(shí)。今天這篇文章我們來(lái)看看一道必會(huì)面試題,即如何實(shí)現(xiàn)一個(gè)深拷貝。本文會(huì)詳細(xì)介紹對(duì)象、數(shù)組、循環(huán)引用、引用丟失、Symbo...
閱讀 736·2021-11-25 09:43
閱讀 1720·2021-11-18 10:02
閱讀 1103·2021-10-15 09:39
閱讀 1953·2021-10-12 10:18
閱讀 2191·2021-09-22 15:43
閱讀 825·2021-09-22 15:10
閱讀 2156·2019-08-30 15:53
閱讀 1069·2019-08-30 13:00