JavaScript深入理解对象方法——Object.assign()
Object.assign()
Object.assign()
方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
语法
Object.assign(target, ...sources)
参数
- target
目标对象。 - sources
源对象。
返回值
目标对象。
描述
如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]
和目标对象的[[Set]]
,所以它会调用相关 getter
和 setter
。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter
,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()
和Object.defineProperty()
。
String
类型和 Symbol
类型的属性都会被拷贝。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError
,如果在引发错误之前添加了任何属性,则可以更改target
对象。
注意,Object.assign
会跳过那些值为 null
或 undefined
的源对象。
示例
复制一个对象
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
深拷贝问题
针对深拷贝,需要使用其他方法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
function test() {'use strict';let obj1 = { a: 0 , b: { c: 0}};let obj2 = Object.assign({}, obj1);console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}obj1.a = 1;console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}obj2.a = 2;console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}obj2.b.c = 3;console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}// Deep Cloneobj1 = { a: 0 , b: { c: 0}};let obj3 = JSON.parse(JSON.stringify(obj1));obj1.a = 4;obj1.b.c = 4;console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
}test();
合并对象
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 }, 注意目标对象自身也会改变。
合并具有相同属性的对象
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);
console.log(obj); // { a: 1, b: 2, c: 3 }
属性被后续参数中具有相同属性的其他对象覆盖。
var o1 = { a: 1 };
var o2 = { [Symbol('foo')]: 2 };var obj = Object.assign({}, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
继承属性和不可枚举属性是不能拷贝的
var obj = Object.create({foo: 1}, { // foo 是个继承属性。bar: {value: 2 // bar 是个不可枚举属性。},baz: {value: 3,enumerable: true // baz 是个自身可枚举属性。}
});var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }
原始类型会被包装为对象
var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo")var obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
异常会打断后续拷贝任务
var target = Object.defineProperty({}, "foo", {value: 1,writable: false
}); // target 的 foo 属性是个只读属性。Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注意这个异常是在拷贝第二个源对象的第二个属性时发生的。console.log(target.bar); // 2,说明第一个源对象拷贝成功了。
console.log(target.foo2); // 3,说明第二个源对象的第一个属性也拷贝成功了。
console.log(target.foo); // 1,只读属性不能被覆盖,所以第二个源对象的第二个属性拷贝失败了。
console.log(target.foo3); // undefined,异常之后 assign 方法就退出了,第三个属性是不会被拷贝到的。
console.log(target.baz); // undefined,第三个源对象更是不会被拷贝到的。
拷贝访问器
var obj = {foo: 1,get bar() {return 2;}
};var copy = Object.assign({}, obj);
// { foo: 1, bar: 2 }
// copy.bar的值来自obj.bar的getter函数的返回值
console.log(copy); // 下面这个函数会拷贝所有自有属性的属性描述符
function completeAssign(target, ...sources) {sources.forEach(source => {let descriptors = Object.keys(source).reduce((descriptors, key) => {descriptors[key] = Object.getOwnPropertyDescriptor(source, key);return descriptors;}, {});// Object.assign 默认也会拷贝可枚举的SymbolsObject.getOwnPropertySymbols(source).forEach(sym => {let descriptor = Object.getOwnPropertyDescriptor(source, sym);if (descriptor.enumerable) {descriptors[sym] = descriptor;}});Object.defineProperties(target, descriptors);});return target;
}var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }
Polyfill
if (typeof Object.assign != 'function') {// Must be writable: true, enumerable: false, configurable: trueObject.defineProperty(Object, "assign", {value: function assign(target, varArgs) { // .length of function is 2'use strict';if (target == null) { // TypeError if undefined or nullthrow new TypeError('Cannot convert undefined or null to object');}var to = Object(target);for (var index = 1; index < arguments.length; index++) {var nextSource = arguments[index];if (nextSource != null) { // Skip over if undefined or nullfor (var nextKey in nextSource) {// Avoid bugs when hasOwnProperty is shadowedif (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {to[nextKey] = nextSource[nextKey];}}}}return to;},writable: true,configurable: true});
}
JavaScript深入理解对象方法——Object.assign()相关推荐
- JavaScript深入理解对象方法——Object.entries()
Object.entries() Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in ...
- es6 javascript对象方法Object.assign()
1 基本用法 Object.assign方法用于对象的合并,将源对象( source )的所有可枚举属性,复制到目标对象( target ). var target = { a: 1 }; var ...
- JavaScript 复制对象与Object.assign方法无法实现深复制
在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...
- js对象新增方法object.assign()
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target). const target = { a: 1 };const source1 = ...
- ES6实用方法Object.assign、defineProperty、Symbol
文章目录 1.合并对象 - Object.assign() 介绍 进阶 注意 用途 2.定义对象 - Object.defineProperty(obj, prop, descriptor) 3.新数 ...
- ecma 2018, javascript spread syntax behaves like Object.assign
as the subject. It is only supported in Chrome version 60+, so, first check the version, or just use ...
- javascript中打印对象显示[object object]_扒一扒JavaScript中不常见的一些object
前言 今天仔细阅读了MDN的这篇guide:Using XMLHttpRequest,在里面发现了好多以前听都没听过的概念,尤其是那些不为人知的Object,所以在这里特地把它们拎出来讲一下,不求多深 ...
- javascript中打印对象显示[object object]_js如何打印object对象
这篇文章主要介绍了js如何打印object对象,需要的朋友可以参考下 js调试中经常会碰到输出的内容是对象而无法打印的时候,光靠alert只能打印出object标示,却不能打印出来里面的内容,甚是不方 ...
- JavaScript中数组对象方法总结
目录 如何创建一个数组 数组的类型转换与检测 解构赋值及三点运算符(展开语法) 数据出栈入栈操作 splice与slice实现数组的增删改查 清空数组的多种操作 拆分和合并 数组的查找 include ...
最新文章
- 常用 Linux 发行版操作系统大盘点!
- ggplot2 图形排版:patchwork 包复杂排版
- 经由因果分析,反驳AI监控学生上课,及辨别健康类谣言
- JavaScript实现浏览器菜单的一些功能
- JAVA中String字符串比较equals()和equalsIgnoreCase()的区别
- _cdecl和_stdcal的区别
- 见良:学习多媒体主要靠实践
- 关于微信“被返回页”在被返回时自动刷新
- 【华为云技术分享】解密TaurusDB存储端高并发之线程池
- 读书笔记系列--《理解专业程序员》tips
- 知识图谱最新研究综述
- VMware ESX的性能如何与Hyper-V的价格进行竞争?
- Centos 5.8 搭建ntp服务器
- 超全超详细Rime中州韵输入法配置指南
- OPPO A59m怎么刷机 OPPO A59m的刷机教程 OPPO A59m完美解除账号锁
- 科密a1无法连接数据库_科密考勤机系统老说数据库连接失败是什么原因?
- 深圳自己做网站 服务器,深圳自己做网站 服务器
- wince 百度地图懒人包_百度导航车载wince版|百度地图winCE版 V10.9.2 安卓版 下载_当下软件园_软件下载...
- 转行做数据分析的心路历程
- 在线制作banner的网站
热门文章
- 从Java代码到Java堆理解和优化您的应用程序的内存使用
- git本地ben远程分支_git 本地分支与远程分支
- opencv乱码java_opencv 放置文字 中文乱码处理 putText
- java helloworld代码_java学习应用篇|逃不掉的HelloWorld
- java8 虚拟机调优_Java虚拟机调优(八)-典型配置举例2
- ios13文件连接服务器教程,iOS 13/iPad OS迈向生产力的一大步,SMB文件共享视频图文教程...
- 使用Asible连接被控端SHH拒绝解决办法
- 高阶数据结构:SSTable
- Zookeeper分布式一致性原理(二):一致性协议
- Starry Night [USACO]