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