摘要:多個(gè)窗口意味著多個(gè)全局環(huán)境,不同的全局環(huán)境擁有不同的全局對(duì)象,從而擁有不同的內(nèi)置類型構(gòu)造函數(shù)。比如,表達(dá)式會(huì)返回,因?yàn)閷傩缘玫降膬H僅是構(gòu)造函數(shù),而且是可以被手動(dòng)更改的,只是返回的構(gòu)造函數(shù)的名字,它并不返回類名。
原文:ES6時(shí)代,你真的會(huì)克隆對(duì)象嗎(二)
上一篇,我們從Symbol和是否可枚舉以及屬性描述符的角度分析了ES6下怎么淺拷貝一個(gè)對(duì)象,發(fā)表在掘金和segmentfault上(其他地方也能看到這篇文章,雖然并沒有人問過我的意見,即便我是同意的,但是連一個(gè)“轉(zhuǎn)”字,一個(gè)原文鏈接都不給,這就很讓人傷心了),從評(píng)論看,部分人覺著看不懂,今天,我們用更簡單的方式來聊聊ES6下深拷貝的問題
寫在前面深拷貝的話題好像從來沒有停止過討論,JavaScript并沒有一個(gè)可以實(shí)現(xiàn)深拷貝的方法,我們常見的實(shí)現(xiàn)方式是遞歸和JSON.parse(JSON.stringify())(聽說底層還是用了遞歸),然而一般庫函數(shù)也只能處理常見的需求(不常見的需求真的存在嗎?真的需要用深拷貝嗎?真的不承認(rèn)是你代碼的問題嗎?)。今天,我就仔細(xì)、認(rèn)真,細(xì)致(也不是很細(xì)致),負(fù)責(zé)(也不敢太保證)的態(tài)度來研究一下怎么實(shí)現(xiàn)一個(gè)深拷貝吧,雖然一度放棄,事實(shí)也的確是放棄了,但不把這么多天的付出寫出來怎么對(duì)得起那個(gè)在這個(gè)寒冷的冬天忍住瑟瑟發(fā)抖的在鍵盤上敲擊的我...
常見深拷貝 JSON系列化JSON.parse(JSON.stringify())的確是一種很簡單易用的方式呢,可惜的是,JSON是一個(gè)很有原則的男人,他可不會(huì)對(duì)你言聽計(jì)從。在遇到不安全的JSON值會(huì)自動(dòng)將其忽略,在數(shù)組中則會(huì)返回null(以保證單元位置不變)。
不安全的 JSON 值: undefined 、 function 、 symbol (ES6+)和包含循環(huán)引用(對(duì)象之間相互引用,形成一個(gè)無限循環(huán))的 對(duì)象 都不符合 JSON 結(jié)構(gòu)標(biāo)準(zhǔn),支持 JSON 的語言無法處理它們遞歸
上一篇講淺拷貝的時(shí)候,我們?cè)陂_始引入了一個(gè)淺拷貝的例子,現(xiàn)在我們把它改成一件簡單的深拷貝。
function deepCopy (obj) { if (typeof obj !== "object") { return } var newObj = obj instanceof Array ? [] : {} for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key] } } return newObj }
好像也還不錯(cuò),簡單易懂還能用,一般的場(chǎng)景的確是一種不錯(cuò)的方法呢,但是,今天我們來看看不一般的場(chǎng)景。
我們先來挑挑毛病:
function類型沒有處理(大概,或許,應(yīng)該是真的沒必要吧,下面我也并不打算討論這貨,有興趣的去看看call、apply、bind)
循環(huán)引用
類型判斷用typeof和instanceof靠譜嗎?(特別注意typeof null的坑)
數(shù)組?[]:{},這么簡單?不存在的
循環(huán)引用上面多處說到了循環(huán)引用的問題,我們先來看看什么是循環(huán)引用:
var a = {} a.b = a
是的,就是這么一個(gè)反人類的存在,但是卻是我們不能忽略的一個(gè)大問題。我們是應(yīng)該返回空呢、undefined呢,還是它的引用,還是什么呢?好像沒有標(biāo)準(zhǔn)答案呢,嗯,那就Follow Your Heart吧!
類型判斷思考一下:
typeof null // "object" null instanceof Object // false
進(jìn)行類型判斷是無可避免的,然而我們似乎并沒有什么完美的方式得到我們需要的類型,我們先來看看幾種常用的方式:
typeof: 返回一個(gè)表達(dá)式的數(shù)據(jù)類型的字符串,返回結(jié)果為js基本的數(shù)據(jù)類型,包括number,boolean,string,object,undefined,function,symbol
instanceof: 判斷一個(gè)對(duì)象是否為某一數(shù)據(jù)類型,或一個(gè)變量是否為一個(gè)對(duì)象的實(shí)例;返回boolean類型。內(nèi)建類型只有通過構(gòu)造器才能用instanceof
constructor: 是每一個(gè)實(shí)例對(duì)象都擁有的屬性,而這個(gè)屬性也相當(dāng)于是一個(gè)指針,它指向于創(chuàng)建當(dāng)前對(duì)象的對(duì)象
Object.prototype.toString.call(obj).slice(8,-1): 返回的是類名
typeof的問題就很明顯了:
typeof null // "object" typeof function () {} // "function" typeof [] // "object"
instanceof考慮一下多全局對(duì)象(多個(gè)frame或多個(gè)window之間的交互),在瀏覽器中,我們的腳本可能需要在多個(gè)窗口之間進(jìn)行交互。多個(gè)窗口意味著多個(gè)全局環(huán)境,不同的全局環(huán)境擁有不同的全局對(duì)象,從而擁有不同的內(nèi)置類型構(gòu)造函數(shù)。這可能會(huì)引發(fā)一些問題。比如,表達(dá)式 [] instanceof window.frames[0].Array 會(huì)返回false,因?yàn)?Array.prototype !== window.frames[0].Array.prototype
constructor屬性得到的僅僅是構(gòu)造函數(shù),而且是可以被手動(dòng)更改的,constructor.name只是返回的構(gòu)造函數(shù)的名字,它并不返回類名。
Object.prototype.toString.call算是比較公認(rèn)靠譜的方法了吧,然而,它同樣有可能被人為仿造,鴨子類型嘛,但它還是比較安全的方式。
鴨子類型: "如果它走起路來像鴨子,叫起來也是鴨子,那么它就是鴨子"。動(dòng)態(tài)類型的語言傾向于你讓它做什么它就是什么類型分析
討論鋪墊的內(nèi)容應(yīng)該夠細(xì)了吧,接下來我們看看js的復(fù)雜數(shù)據(jù)類型到底有多復(fù)雜。
我們常見的有:
基本包裝類型(Boolean、String、Number)、function、Array、Date
你常見,但你不一定想的起的:
RegExp,Arguments,Error、NodeList
你不一定常見,你也不一定知道的:
Blob、File、FileList、ImageData
ES6:
Map、Set、WeakMap、WeakSet、ArrayBuffer對(duì)象、TypedArray視圖和DataView視圖、Float32Array、Float64Array、Int8Array...
或許列舉的少了不少,但是已經(jīng)夠讓人擔(dān)憂深克隆的復(fù)雜程度了,一一實(shí)現(xiàn)他們不是一件簡單的事情,甚至是一件完全沒有必要的事情(當(dāng)然可以讓你了解更多),推薦幾個(gè)很優(yōu)秀的方案供參考:
lodash克隆,lodash花了大量的代碼來實(shí)現(xiàn) ES6 引入的大量新的標(biāo)準(zhǔn)對(duì)象。更厲害的是,lodash 針對(duì)存在環(huán)的對(duì)象的處理也是非常出色的
jQuery克隆無法正確深復(fù)制 JSON 對(duì)象以外的對(duì)象
結(jié)構(gòu)化克隆算法
寫在最后克隆的部分就寫的差不多了,本來想寫點(diǎn)Map、Set的內(nèi)容的,無賴,并沒有找到合適的地方,MDN、阮一峰的ECMAScript 6 入門都介紹的挺好的。
好吧,就這樣吧,前端界的小學(xué)生,不足之處,還請(qǐng)指正
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107228.html
摘要:原文你真的會(huì)克隆對(duì)象嗎開始之前在開始聊克隆之前,我們還是先來看看數(shù)據(jù)類型。值通過函數(shù)生成,是獨(dú)一無二的。同時(shí),中規(guī)定了對(duì)象的屬性名有兩種類型,一種是字符串,另一種就是類型。返回一個(gè)數(shù)組,包含對(duì)象自身的所有屬性的鍵名。 原文:你真的會(huì)克隆對(duì)象嗎 開始之前 在開始聊克隆之前,我們還是先來看看js數(shù)據(jù)類型。js的數(shù)據(jù)類型分為基本數(shù)據(jù)類型和復(fù)雜數(shù)據(jù)類型。 基本數(shù)據(jù)類型:Number、Bool...
摘要:新增了二個(gè)聲明變量的關(guān)鍵字,和,再加上之前的,這樣聲明變量就有三個(gè)關(guān)鍵字了,大有三國鼎立之勢(shì)。當(dāng)?shù)闹禐闀r(shí),該變量不會(huì)被聲明并初始化。如果上面的那個(gè)循環(huán)中用聲明變量,那么循環(huán)完了,變量也就隨時(shí)銷毀,不能再被訪問。 ES6新增了二個(gè)聲明變量的關(guān)鍵字,let和const,再加上ES6之前的var,這樣聲明變量就有三個(gè)關(guān)鍵字了,大有三國鼎立之勢(shì)。那到底用哪個(gè)來聲明變量呢? var 首先,得說說...
摘要:最近在代碼中不小心不規(guī)范的,在里面定義了塊級(jí)變量,導(dǎo)致頁面在某些瀏覽器中出錯(cuò),本文討論以下語句中的塊級(jí)作用域。而與無關(guān)每一個(gè)并不會(huì)構(gòu)成一個(gè)獨(dú)立的塊級(jí)作用域。 ??最近在代碼中不小心不規(guī)范的,在switch里面定義了塊級(jí)變量,導(dǎo)致頁面在某些瀏覽器中出錯(cuò),本文討論以下switch語句中的塊級(jí)作用域。 switch語句中的塊級(jí)作用域 switch語句中的塊級(jí)作用域可能存在的問題 規(guī)范和檢...
摘要:最近在代碼中不小心不規(guī)范的,在里面定義了塊級(jí)變量,導(dǎo)致頁面在某些瀏覽器中出錯(cuò),本文討論以下語句中的塊級(jí)作用域。而與無關(guān)每一個(gè)并不會(huì)構(gòu)成一個(gè)獨(dú)立的塊級(jí)作用域。 ??最近在代碼中不小心不規(guī)范的,在switch里面定義了塊級(jí)變量,導(dǎo)致頁面在某些瀏覽器中出錯(cuò),本文討論以下switch語句中的塊級(jí)作用域。 switch語句中的塊級(jí)作用域 switch語句中的塊級(jí)作用域可能存在的問題 規(guī)范和檢...
閱讀 6912·2021-09-22 15:08
閱讀 1920·2021-08-24 10:03
閱讀 2437·2021-08-20 09:36
閱讀 1315·2020-12-03 17:22
閱讀 2474·2019-08-30 15:55
閱讀 905·2019-08-29 16:13
閱讀 3053·2019-08-29 12:41
閱讀 3249·2019-08-26 12:12