摘要:后續(xù)我將推出進階系列,一方面是一個監(jiān)督自己學習的一個過程,另一方面也會給看到的童鞋一些啟發(fā)。第二步鏈接到原型中現(xiàn)在把構造函數(shù)和參數(shù)都打印出來了。
原文:https://zhehuaxuan.github.io/...寫在前面的話
作者:zhehuaxuan
前端的入門相對簡單,相對于其他方向天花板可能會相對較低。但是在市場上一個優(yōu)秀的前端依舊是很搶手的。能夠站在金字塔上的人往往寥寥無幾。
目前前端也已經一年半了,在公司的知識棧相對落后,就業(yè)形勢不容樂觀,所以有必要自己琢磨,往中高級前端進階。后續(xù)我將推出《JavaScript進階系列》,一方面是一個監(jiān)督自己學習的一個過程,另一方面也會給看到的童鞋一些啟發(fā)。
JavaScript新建對象的過程在ES5中定義一個函數(shù)來創(chuàng)建對象,如下:
function Person(name){ this.name = name; } Person.prototype.getName = function(){ return name; } var person = new Person("xuan"); console.log(person.name);//輸出:xuan console.log(person.getName());//輸出:xuan
我們看到當我們新建一個對象,我們就可以訪問構造器中的指向this的屬性,還可以訪問原型中的屬性。我們不妨把JavaScript調用new的過程主要由下面四步組成:
新生成一個空對象
將空對象鏈接到原型中
綁定this
返回新對象
下面跟著我按照這個思路來創(chuàng)建對象:
function create(){ //Todo } person = create(Person,"xuan");//create(ObjectName,...arguments)
我們使用如上所示的函數(shù)來模擬new關鍵字。
首先第一步新建一個對象:
function create(){ var obj = new Object(); return obj; } person = create(Person,"xuan");
現(xiàn)在已經創(chuàng)建并返回一個對象,當然現(xiàn)在打印出來肯定是一個普通的對象,畢竟流程還沒有走完,我們接著往下看。
第二步鏈接到原型中:
function create(){ var obj = new Object(); var constructor = [].shift.call(arguments); console.log(constructor); console.log(arguments); obj.__proto__ = constructor.prototype; return obj; } person = create(Person,"xuan");
現(xiàn)在把構造函數(shù)和參數(shù)都打印出來了。沒問題!
第三步綁定this,如下:
function create() { let obj = new Object(); let constructor = [].shift.call(arguments) obj.__proto__ = constructor.prototype constructor.apply(obj, arguments); console.log(obj); return obj; } person = create(Person,"xuan");
打印結果實現(xiàn)new對象的效果。
現(xiàn)在改一下構造函數(shù)代碼:
function Person(name){ this.name = name; return { name:"abc" } } var person = new Person("xuan"); console.log(person); console.log(Object.prototype.toString.call(person));
效果如下:
我們執(zhí)行一下我們構建的函數(shù)效果如下:
發(fā)現(xiàn)不一致,所以我們要處理第三步綁定this中apply函數(shù)的返回值:
function create() { let obj = new Object(); let constructor = [].shift.call(arguments) obj.__proto__ = constructor.prototype //constructor.apply(obj, arguments); let res = constructor.apply(obj, arguments); if(res){ return res; }else{ return obj; } } person = create(Person,"xuan");
效果如下:
完美!
現(xiàn)在我們思考一下這里的res返回值有三種情況:undefined,基本類型,對象。
如果res是undefined時,返回obj;如果res是基本類型我們也返回obj;
如果res是對象我們返回res對象;
綜合一下:
如果返回的res對象是Object類型那么返回res,否則返回obj。當然其他的判斷條件也是可以的。最后代碼優(yōu)化如下:
function create() { let obj = new Object(); let constructor = [].shift.call(arguments) obj.__proto__ = constructor.prototype //constructor.apply(obj, arguments); let res = constructor.apply(obj, arguments); return res instanceof Object?res:obj; } person = create(Person,"xuan");幾個問題
現(xiàn)在的代碼已經完美了么?我們先來提幾個問題。
new Object()創(chuàng)建的對象純凈么?new Object()創(chuàng)建的對象純凈么?
為啥使用[].shift.call()來進行參數(shù)分割?arguments是一個數(shù)組么?
首先什么是純凈?我們定義一個對象的__proto__屬性為空的對象是一個純凈的對象。
在第二步的時候中已經改變的obj的原型鏈,所以無論它前面的原型鏈是咋樣的都無所謂,但是為了保證對象的純凈性,我們有必要引出Object.create(),該方法創(chuàng)建一個新對象,使用現(xiàn)有的對象來提供新創(chuàng)建的對象的__proto__。我們來看一下:
var person1 = Object.create({});
打印如下:
我們看到person1的__proto__指向了{}對象,所以我們在上述代碼中直接修改如下:
function create() { let constructor = [].shift.call(arguments); let obj = Object.create(constructor.prototype); let res = constructor.apply(obj, arguments); return res instanceof Object?res:obj; } person = create(Person,"xuan");為啥使用[].shift.call()來進行參數(shù)分割?arguments是一個數(shù)組么?
首先我們知道arguments是函數(shù)傳入的參數(shù),那么這個參數(shù)是數(shù)組么?我們打印一下便知:
console.log(arguments); console.log(Object.prototype.toString.call(arguments)); console.log(arguments instanceof Array);
結果如下
不是數(shù)組。我們展開發(fā)現(xiàn)他跟數(shù)組很像,查一下資料發(fā)現(xiàn)這個對象是類數(shù)組。里面沒有shift函數(shù),直接調用shift會報錯。我們使用使用Array.from(arguments)將arguments轉成數(shù)組,然后在調用shift函數(shù)也是一種思路。但是在這里我們使用apply最適合。所以下述代碼是模擬new Object()的最優(yōu)代碼:
function create() { let constructor = [].shift.call(arguments); let obj = Object.create(constructor.prototype); let res = constructor.apply(obj, arguments); return res instanceof Object?res:obj; } person = create(Person,"xuan");
還有更優(yōu)的實現(xiàn)方法,請大佬們不吝拍磚!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/102538.html
摘要:使用指定的參數(shù)調用構造函數(shù),并將綁定到新創(chuàng)建的對象。由構造函數(shù)返回的對象就是表達式的結果。情況返回以外的基本類型實例中只能訪問到構造函數(shù)中的屬性,和情況完全相反,結果相當于沒有返回值。 定義 new 運算符創(chuàng)建一個用戶定義的對象類型的實例或具有構造函數(shù)的內置對象的實例。 ——(來自于MDN) 舉個栗子 function Car(color) { this.color = co...
摘要:之前文章詳細介紹了的使用,不了解的查看進階期。不同的引擎有不同的限制,核心限制在,有些引擎會拋出異常,有些不拋出異常但丟失多余參數(shù)。存儲的對象能動態(tài)增多和減少,并且可以存儲任何值。這邊采用方法來實現(xiàn),拼成一個函數(shù)。 之前文章詳細介紹了 this 的使用,不了解的查看【進階3-1期】。 call() 和 apply() call() 方法調用一個函數(shù), 其具有一個指定的 this 值和分...
摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對象這種行為就像把原函數(shù)當成構造器,提供的值被忽略,同時調用時的參數(shù)被提供給模擬函數(shù)。 bind() bind() 方法會創(chuàng)建一個新函數(shù),當這個新函數(shù)被調用時,它的 this 值是傳遞給 bind() 的第一個參數(shù),傳入bind方法的第二個以及以后的參數(shù)加上綁定函數(shù)運行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調用原函數(shù)。bind返回的綁定函數(shù)也能使用 n...
摘要:今天這篇文章我們來看看一道必會面試題,即如何實現(xiàn)一個深拷貝。木易楊注意這里使用上面測試用例測試一下一個簡單的深拷貝就完成了,但是這個實現(xiàn)還存在很多問題。 引言 上篇文章詳細介紹了淺拷貝 Object.assign,并對其進行了模擬實現(xiàn),在實現(xiàn)的過程中,介紹了很多基礎知識。今天這篇文章我們來看看一道必會面試題,即如何實現(xiàn)一個深拷貝。本文會詳細介紹對象、數(shù)組、循環(huán)引用、引用丟失、Symbo...
摘要:引言上一節(jié)介紹了高階函數(shù)的定義,并結合實例說明了使用高階函數(shù)和不使用高階函數(shù)的情況。我們期望函數(shù)輸出,但是實際上調用柯里化函數(shù)時,所以調用時就已經執(zhí)行并輸出了,而不是理想中的返回閉包函數(shù),所以后續(xù)調用將會報錯。引言 上一節(jié)介紹了高階函數(shù)的定義,并結合實例說明了使用高階函數(shù)和不使用高階函數(shù)的情況。后面幾部分將結合實際應用場景介紹高階函數(shù)的應用,本節(jié)先來聊聊函數(shù)柯里化,通過介紹其定義、比較常見的...
閱讀 3022·2021-11-23 09:51
閱讀 1016·2021-09-26 09:55
閱讀 3972·2021-09-22 14:58
閱讀 1504·2021-09-08 09:35
閱讀 1086·2021-08-26 14:16
閱讀 891·2019-08-23 18:17
閱讀 2073·2019-08-23 16:45
閱讀 710·2019-08-23 15:55