摘要:方法用于對象的合并,將所有自身的非繼承的可枚舉屬性的值從一個或多個源對象拷貝到目標對象。比如,如果對象的屬性是函數或對象,該屬性會被過濾掉,導致拷貝時會缺少屬性。利用遞歸對每一層都重新創建對象并賦值從而實現深拷貝
Object.assign()
Object.assign() 方法用于對象的合并,將所有自身的(非繼承的)可枚舉屬性的值從一個或多個源對象拷貝到目標對象。返回目標對象。目標對象自身也會改變。
Object.assign(target, ...sources)
target: 目標對象。
sources: 源對象。
Object.assign() 合并拷貝屬性的限制只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)。
Object.assign({b: "c"}, Object.defineProperty({}, "invisible", { enumerable: false, value: "hello" }) ) // { b: "c" }參數類型 1. 只有一個參數
如果只有一個參數,Object.assign() 會直接返回該參數。
let obj = {a: 1}; Object.assign(obj) === obj // true
如果該參數不是對象,則會先轉成對象,然后返回。
typeof Object.assign(2) // "object"
由于 undefined 和 null 無法轉成對象,所以如果它們作為參數,就會報錯。
Object.assign(undefined) // 報錯 Object.assign(null) // 報錯2. 對象 + 非對象
非對象參數都會轉成對象,如果無法轉成對象,就會跳過,不會報錯。
如果非對象參數為 undefined 和 null ,就會跳過,不會報錯,返回的依舊是目標對象參數。
let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true
如果非對象參數為其他類型的值(即數值、字符串和布爾值),也不會報錯。但是,除了字符串會以數組形式拷貝入目標對象,其他值都不會產生效果。這是因為只有字符串的包裝對象,會產生可枚舉屬性。
let v1 = "abc"; let v2 = true; let v3 = 10; let obj = Object.assign({}, v1, v2, v3); console.log(obj) // { "0": "a", "1": "b", "2": "c" }3. 目標對象 + 源對象...
Object.assign() 不會跳過那些屬性值為 null 或 undefined 的源對象。
var o1 = { a: null, b: 1}; var o2 = { c: undefined }; var obj = Object.assign({}, o1, o2); obj // {a: null, b: 1, c: undefined}
如果目標對象與源對象中的屬性具有相同的鍵,則目標對象屬性將被源中的屬性覆蓋。后來的源的屬性將類似地覆蓋早先的屬性。
var o1 = { a: 1, b: 1, c: 1 }; var o2 = { b: 2, c: 2 }; var o3 = { c: 3 }; var obj = Object.assign({}, o1, o2, o3); obj // { a: 1, b: 2, c: 3 }
Object.assign() 方法實行的是淺拷貝,而不是深拷貝??截惖氖菍傩灾怠<偃缭磳ο蟮膶傩灾凳且粋€指向對象的引用,它也只拷貝那個引用值。
var obj1 = { a: 0 , b: { c: 0 } }; var obj2 = Object.assign({}, obj1); obj2 // { a: 0, b: { c: 0 } }; obj2.b.c = 3; obj1 // { a: 0, b: { c: 3 } }; obj2 // { a: 0, b: { c: 3 } };
Object.assign() 可以用來處理數組,但是會把數組視為鍵值為數組下標的對象來合并,然而最終的返回形式也是數組。
Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3] Object.assign({0:1,1:2,2:3},{0:4,1:5}) // {0: 4, 1: 5, 2: 3}
Object.assign() 如果遇到存取器定義的屬性,會只拷貝值。
var obj = { foo: 1, get bar() { return 2; } }; var copy = Object.assign({}, obj); copy // { foo: 1, bar: 2 }
因此必須使用 Object.getOwnPropertyDescriptors() 方法配合 Object.defineProperties() 方法,就可以實現正確拷貝。但僅限于可拷貝 getter 和 setter ,對于屬性的引用類型還是屬于淺拷貝。
var obj = { foo: { a : 0 }, get bar() { return 2; } }; var target = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj) ); Object.getOwnPropertyDescriptor(target, "bar") // { get : ? bar(), set : undefined, enumerable : true, configurable : true } obj.foo.a = 6 target.foo.a // 6常見用途 1. 為對象添加屬性
class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
上面方法通過 Object.assign() 方法,將 x 屬性和 y 屬性添加到 Point 類的對象實例。
2. 為對象添加方法Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同于下面的寫法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };3. 淺克隆對象
let obj = {a:5}; function clone(origin) { return Object.assign({}, origin); } let aaa = clone(obj); // {a:5}
不過,采用這種方法克隆,只能克隆原始對象自身的值,不能克隆它繼承的值。如果想要保持繼承鏈,可以采用下面的代碼。
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }4. 合并多個對象
let merge = (target, ...sources) => Object.assign(target, ...sources);
如果希望合并后返回一個新對象,可以改寫上面函數,對一個空對象合并。
let merge = (...sources) => Object.assign({}, ...sources);5. 為屬性指定默認值
const DEFAULTS = { a: 0, b: "ccc" }; function copy(options) { options = Object.assign({}, DEFAULTS, options); // ... }
注意,由于存在淺拷貝的問題,DEFAULTS對象和options對象的所有屬性的值,最好都是簡單類型,不要指向另一個對象。否則,DEFAULTS對象的該屬性很可能不起作用。
參考鏈接:Object.assign()
深拷貝 1. JSON.parse(JSON.stringify(obj))var obj1 = { a: 0 , b: { c: 0}}; var obj2 = JSON.parse(JSON.stringify(obj1)); obj1.b.c = 4; obj2 // { a: 0, b: { c: 0}}
但由于 JSON 的局限性,該方法也不是萬能的。比如,如果對象的屬性是 undefined、函數、symbol 或 XML 對象,該屬性會被 JSON.stringify() 過濾掉,導致拷貝時會缺少屬性。
let obj = { name:"dora", sayHello:function(){ console.log("Hello World"); } } let cloneObj = JSON.parse(JSON.stringify(obj)); console.log(cloneObj); // {name: "dora"}2. 利用遞歸對每一層都重新創建對象并賦值從而實現深拷貝
function deepClone(source){ let targetObj = source.constructor === Array ? [] : {}; for(let keys in source){ if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === "object"){ targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepClone(source[keys]); }else{ targetObj[keys] = source[keys]; } } } return targetObj; } let obj = { a: { b: 1, c: 2 }, sayHello: function(){ console.log("Hello World"); } } let cloneObj = deepClone(obj); obj.a.b = 4 obj // {a:{b: 4, c: 2},sayHello:? ()} cloneObj // {a:{b: 1, c: 2},sayHello:? ()}
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101125.html
摘要:上一篇文章實用技法第篇對齊文本字符串下一篇文章問題我們想將許多小字符串合并成一個大的字符串。示例如下對于不必要的字符串連接操作也要引起重視。有時候在技術上并非必需的時候,程序員們也會忘乎所以地使用字符串連接操作。 上一篇文章: Python實用技法第32篇:對齊文本字符串下一篇文章: 問題 我們想將許多小字符串合并成一個大的字符串。 解決方案 如果想要合并的字符串在一個序列或可迭代...
摘要:但這兩種拷貝有一個問題就是只能賦值一層,假設我們有如下數據結構臧三小明小芳我們會發現打印出的結果如下上圖可看出的結果均變了,這并不是我們想要的結果,所以我們要用到深拷貝。 一個項目開發中經常會用到需要復制一個對象或者數組,但是卻不能改變原始對象,所以就要用到拷貝,拷貝又分深拷貝和淺拷貝,今天列舉一下幾種拷貝形式。 一、淺拷貝 (1) Object.assign() Object.ass...
摘要:一切對象都是的實例,一切函數都是的實例,是構造函數,函數是的實例,是對象,對象是的實例,可以說與是一對密不可分的兄弟,讓我們一起解開與的神秘面紗,本章主要了解相關知識,下章再來看構造函數可以創建一個對象包裝器中所有對象都來自所有對象從繼承方 一切對象都是 Object 的實例,一切函數都是 Function 的實例,Object 是構造函數,函數是 Function 的實例,Funct...
摘要:接下來就讓我們更細致的探究中的深淺拷貝??偨Y以上對深拷貝和淺拷貝做了簡單的介紹,在深拷貝的實現上也只介紹了最簡單的實現形式,并未考慮復雜情況以及相應優化,想要對深拷貝有更深入的了解,需要大家花時間去深入研究,或者可以關注我后續文章的動態。 對象和數組的拷貝對我來說一直都是一個比較模糊的概念,一直有點一知半解,但是在實際工作中又偶爾會涉及到,有時候還會一不小心掉坑里,不知道大家有沒有同樣...
摘要:深拷貝淺拷貝本文主要對深拷貝淺拷貝的解釋及實現做一下簡單記錄。之所以會有深拷貝與淺拷貝之分,是因為不同數據類型的數據在內存中的存儲區域不一樣。但注意,只能做一層屬性的淺拷貝。 深拷貝VS淺拷貝 本文主要對深拷貝&淺拷貝的解釋及實現做一下簡單記錄。原文鏈接,歡迎star。 之所以會有深拷貝與淺拷貝之分,是因為不同數據類型的數據在內存中的存儲區域不一樣。 堆和棧是計算機中劃分出來用來存儲的...
閱讀 1684·2023-04-25 20:16
閱讀 3838·2021-10-09 09:54
閱讀 2696·2021-09-04 16:40
閱讀 2517·2019-08-30 15:55
閱讀 830·2019-08-29 12:37
閱讀 2733·2019-08-26 13:55
閱讀 2903·2019-08-26 11:42
閱讀 3144·2019-08-23 18:26