[轉]理解Object.assign

来源:http://www.cnblogs.com/2010master/archive/2017/02/17/6410415.html
-Advertisement-
Play Games

本節內容我們繼續探討關於ES2015的一些新的內容,Object.assign函數的使用,使用該函數我們可以快速的複製一個或者多個對象到目標對象中,本文內容涉及es6,es7相關的對象複製的內容,以及一些es5的替代方案的介紹。 函數原型 首先看一下函數的定義: 函數參數為一個目標對象(該對象作為最 ...


本節內容我們繼續探討關於ES2015的一些新的內容,Object.assign函數的使用,使用該函數我們可以快速的複製一個或者多個對象到目標對象中,本文內容涉及es6,es7相關的對象複製的內容,以及一些es5的替代方案的介紹。

函數原型

首先看一下函數的定義: 函數參數為一個目標對象(該對象作為最終的返回值),源對象(此處可以為任意多個)。通過調用該函數可以拷貝所有可被枚舉的自有屬性值到目標對象中。

Object.assign(target, ...sources)

這裡我們需要強調的三點是:

  1. 可被枚舉的屬性
  2. 自有屬性
  3. string或者Symbol類型是可以被直接分配的

拷貝過程中將調用源對象的getter方法,併在target對象上使用setter方法實現目標對象的拷貝。

函數實例

這裡我們通過幾個MDN上的例子來介紹一下使用方法:

實例一

我們參考上面的原型函數說明即可知道其最開始的o1因為設置為target,則調用其setter方法設置了其他對象的屬性到自身。

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.

實例二

我們自定義了一些對象,這些對象有一些包含了不可枚舉的屬性,另外註意使用 Object.defineProperty 初始化的對象預設是不可枚舉的屬性。對於可枚舉的對象我們可以直接使用Object.keys()獲得,或者使用for-in迴圈遍歷出來.

對於不可枚舉的屬性,使用Object.assign的時候將被自動忽略。

var obj = Object.create({ foo: 1 }, { // foo is an inherit property.
  bar: {
    value: 2  // bar is a non-enumerable property.
  },
  baz: {
    value: 3,
    enumerable: true  // baz is an own enumerable property.
  }
});

var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }  

實例三

對於只讀的屬性,當分配新的對象覆蓋他的時候,將拋出異常:

var target = Object.defineProperty({}, 'foo', {
  value: 1,
  writable: false
}); 

Object.assign(target, { bar: 2 })

//{bar: 2, foo: 1}

Object.assign(target, { foo: 2 })
//Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>'(…)

Polyfill

這裡我們簡單的看下如何實現es5版本的Object.assign:

實現步驟:

  1. 判斷是否原生支持該函數,如果不存在的話創建一個立即執行函數,該函數將創建一個assign函數綁定到Object上。
  2. 判斷參數是否正確(目的對象不能為空,我們可以直接設置{}傳遞進去,但必須設置該值)
  3. 使用Object在原有的對象基礎上返回該對象,並保存為out
  4. 使用for…in迴圈遍歷出所有的可枚舉的自有對象。並複製給新的目標對象(hasOwnProperty返回非原型鏈上的屬性)

源碼如下:

 if (typeof Object.assign != 'function') {
  (function () {
	Object.assign = function (target) {
	 'use strict';
	 if (target === undefined || target === null) {
	   throw new TypeError('Cannot convert undefined or null to object');
	 }
	
	 var output = Object(target);
	 for (var index = 1; index < arguments.length; index++) {
	   var source = arguments[index];
	   if (source !== undefined && source !== null) {
	     for (var nextKey in source) {
	       if (source.hasOwnProperty(nextKey)) {
	         output[nextKey] = source[nextKey];
	       }
	     }
	   }
	 }
	 return output;
	};
})();
}

擴展內容

1.深度複製

當我們調用下麵的函數的時候,由於Object.assign將覆蓋之前的內容,所以並不能完全的做到融合對象,而是全部替換掉,所以返回的對象內容將變成最後一個值; {a: {c: 3}

Object.assign({a: {b: 0}}, {a: {b: 1, c: 2}}, {a: {c: 3}});

如何深層次的融合對象,比如我們期望的輸出結果為:

{a:{b:1,c:3}}

這樣我們必須實現自己的演算法來完成深層複製了,不過github上已經有很多好的解決方案,比如deep-merge 通過遞歸的方式逐層的去調用assign函數。

2.ES2016實現

在es7中我們使用rest屬性可以捕獲所有剩餘的對象內容比如下麵的例子(可使用babel-repl頁面測試,瀏覽器一般尚未支持):

let { fname, lname, ...rest } = { fname: "Hemanth", lname: "HM", location: "Earth", type: "Human" };
fname; //"Hemanth"
lname; //"HM"
rest; // {location: "Earth", type: "Human"}

這樣我們就可以使用該特性來實現assign函數

let oldObj1={a:"a",b:{b1:"b1"}}
let oldObj2={a:"a1",b:{b2:"b2"},c:"c"}

let newObject={...oldObj1,...oldObj2};
console.log(newObject)

{"a":"a1","b":{"b2":"b2"},"c":"c"}

不過仍舊只是淺層的替換,並沒有實現深層次的合併。

 

原文地址: https://cnodejs.org/topic/56c49662db16d3343df34b13


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • extends與implements的不同 1、在類的聲明中,通過關鍵字extends來創建一個類的子類。 一個類通過關鍵字implements聲明自己使用一個或者多個介面。 extends 是繼承某個類, 繼承之後可以使用父類的方法, 也可以重寫父類的方法; implements 是實現多個介面, ...
  • 今天我們來講一下橋接模式。 一、案例 我有N牌子的一個手機,需要運行一款游戲軟體。咱們用簡單的控制台應用程式來實現一下。 客戶端調用: 二、演繹 1、第一步演繹: 如果我不僅有N品牌的手機,還有M品牌的手機也需要運行這款游戲軟體,怎麼辦? 我們可以將運行游戲軟體抽象出一個父類,讓N,M品牌的手機繼承 ...
  • 很久沒寫博客了,因為最近在用react+express做一個自己的工具型網站(其實就是奪寶島搶拍器) 然後因為經常要改動,而且又要放到伺服器上進行測試。總是要webpack,然後手動把文件上傳上去,不勝其煩,索性搜索了下,直接寫個能檢測文件變化並自動進行上傳的腳本好了。 首先,我們使用npm 安裝兩 ...
  • 什麼是webpack webpack是一個模塊化載入器 支持AMD/CMD。 webpack優勢 代碼分割 Loaders 插件機制 ... 安裝webpack 全局安裝 局部安裝 安裝某個指定的版本 例如1.14.0 webpack命令行參數 p 編譯後會壓縮文件 w/ watch 開發環境下會監 ...
  • //先定義一個數組 anular代碼: var app = angular.module('serApp', []); app.controller('indexCtrl', function($scope, $http) { $scope.arrs = [{ n:'a'; arr:['1','2' ...
  • DOM事件模型 在0級DOM事件模型中,它只是簡單的執行你為它綁定的事件,比如你為某個元素添加了一個onclick事件,當事件觸發時,它只是去調用我們綁定的那個方法,不再做其他的操作。 在2級DOM事件模型中,就比較複雜一些,它將不再是單純的調用一下自身綁定的事件就完事了,它還擁有機會去處理它的祖先 ...
  • 在發送簡訊息驗證碼的時候要用到js設置時間倒序問題:有時候這種常規寫法會導致js失效,試了很多方法才找到問題所在,可能是因為js版本過低導致。 解決方法: jquery代碼:必須用input設置value值,以便利用jquery更改value值 ...
  • 作為一名準前端開發工程師,必須要對http基礎知識有一定的瞭解,可是想學習HTTP相關的知識,發現國內只有兩本相關的圖書,《HTTP權威指南》和《圖解http》,所有的書但凡帶上權威指南,必將是聖經級別的圖書,我在學校圖書館借了一本,600多頁的磚頭書,由於基礎太過薄弱,根本讀不下去,於是轉向了《圖 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...