Object.assign()
将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象。
Object.assign(target, ...sources)
不会跳过值为null或undefined 的源对象。
深拷贝问题
Object.assign() 拷贝的是属性值,如果源对象的属性值是一个对象的应用,它就会指向那个引用。【浅拷贝】
let obj1 = {a: 0, b: { c: 0 }}
let obj2 = Object.assign({}, obj1)
let obj3 = JSON.parse(JSON.stringify(obj1)) // 可做深拷贝
obj1.a = 4;
obj1.b.c = 4;
console.log(obj1) // {a: 4, b: {c: 4}}
console.log(obj2) // {a: 0, b: {c: 4}}
console.log(obj3) // {a: 0, b: {c: 0}}
合并对象
let o1 = { a: 1 , b: 1, c: 1}
let o2 = { b:2, c: 2 }
let o3 = { c: 3 }
const obj = Object.assign(o1, o2, o3);
console.log(obj) // {a: 1, b: 2, c: 3 }
console.log(o1) // {a: 1, b: 2, c: 3 }
目标对象会改变, 相同属性会被后面的属性覆盖。
拷贝 symbol 类型的属性
const o1 = {a: 1}
const o2 = {[Symbol('foo')]: 2}
const obj = Object.assign(o1, o2)
console.log(obj) // {a: 1, [Symbol('foo')]: 2}
Object.getOwnPropertySymbols(obj) // [Symbol(foo)]
继承属性和不可枚举属性是不能拷贝的
const obj = Object.crate({foo: 1}, {
bar: {
value: 2 // 不可枚举属性
},
baz: {
value: 3,
enumerable: true // 可枚举属性
}
})
const copy = Object.assign({}, obj)
console.log(copy) // {baz: 3}
原始类型会被包装为对象
const v1 = "abc"
const v2 = true
const v3 = 10
const v4 = Symbol('foo')
const obj = Object.assign({}, v1, null, v2, undefined, v3, v4)
conosle.log(obj) // { "0": "a", "1": "b", "2": "c" }
原始类型会被包装, null 和 undefined 会被忽略。
注意: 只有字符串的包装对象才可能有自身可枚举属性。
拷贝访问器
const obj = {
foo: 1,
get bar() {
return 2
}
}
let copy = Object.assign({}, obj)
console.log(copy) // {foo: 1, bar: 2}
// 拷贝所有自身属性的属性描述符
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 默认也会拷贝可枚举属性
Object.getOwnPropertySymbols(source).forEach(sym => {
let descriptor = Object.getOwnPropertyDescriptor(source, sym)
if (descriptor.enumerable) {
descriptors[sym] = descriptor
}
})
Object.defineProperties(target, descriptors);
})
return target;
}
let deepCopy = completeAssign({}, obj) // { foo: 1, get bar() { return 2 }}
Object.create()
Object.create(proto, [propertiesObject])
proto 新创建对象的原型对象。
propertiesObject 要添加到新创建对象的可枚举属性对象的属性描述符以及相应的属性名称。
const person = {
isHuman: false,
printIntroduction: function() {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`)
}
}
const me = Object.create(person)
me.name = "Matthew"
me.isHuman = true
my.printIntroduction();
"My name is Matthew. Am I Human? true"
let o = Object.create(null) // {}
let o2 = Object.create(Object.prototype) // {}
let o3 = Object.create(Object.prototype, {
foo: {
writable: true,
configurable: true,
value: 'hello'
},
bar: {
configurable: false,
get: function() { return 10 },
set: function(val) {
console.log('setting `o.bar` to', value)
}
}
})
// o3 = {
bar: 10,
foo: "hello",
get bar: ƒ (),
set bar: ƒ (val)
}
Object.defineProperties()
直接在一个对象上定义新的属性或修改现有属性,并返回该对对象。
/***
* Object.defineProperties(obj, props)
*
* props => 属性+属性描述符
* value => undefined; 属性值
* configurable => false; 可配置【删除,修改】
* enumerable => false; 可枚举
* writable => false; 可写性
* get => undefined; 函数返回值将被用作属性值
* set => undefined; 将参数值作为该属性的新值
*/
let obj = {};
Object.defineProperties(obj, {
'name': {
value: '张三',
writable: false,
},
'age': {
value: 20,
writable: true,
},
'love': {
value: 'football',
configurable: fale,
}
});
obj.name = '张无忌';
obj.age = 18;
delete obj.love;
console.log(obj)
Object.definePropery()
直接在一个对象上定义一个新的属性,或修改一个对象的现有属性,并返回这个对象。
/***
* Object.defineProperty(obj, prop, descriptor)
*
* prop 要定义或修改的属性
* descriptor 属性描述符
* return 被传递给函数的对象
*/
let o = {};
o.a = 1;
// 等同于
Object.difineProperty(o, 'a', {
value: 1,
writeable: true,
configurable: true,
enumerable: true,
});
Object.defineProperty(o, "name", {value: 1});
// 等同于
Object.defineProperty(o, 'name', {
value: 1,
writable: false,
configurable: false,
enumerable: false,
})
Object.freeze()
冻结一个对象,冻结对象不能修改、添加、删除,也不饿能改变该对象的可枚举性,可配置性,可写。
// 冻结对象
let obj = {prop: 42};
Object.freeze(obj);
obj.prop = 33;
delete obj.prop;
console.log(obj.prop);
// 冻结数组
let arr = [1, 2];
Object.freeze(arr);
arr[0] = 11;
// arr.push(33);
console.log(arr);
// 深冻结
function deepFreeze(obj) {
let propNames = Object.getOwnPropertyNames(obj);
// 冻结自身前冻结属性
propNames.forEach((name) => {
let prop = obj[name];
// 如果是一个对象,冻结它
if (typeof prop=='object' & prop!=null) {
deepFreeze(prop);
}
});
return Object.freeze(obj);
}
let obj2 = {
internal: {
a: 'hello'
}
};
deepFreeze(obj2);
obj2.internal.a = 'anotherValue';
console.log(obj2.internal.a);
Object.seal()
封闭一个对象,阻止添加新属性并把所有现有对象标记为不可配置。但只要当前属性时可写的就可以改变。
let obj = {
prop: function() {},
foo: 'bar',
};
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;
let o = Object.seal(obj);
console.log(o === obj); // true
console.log(Object.isSealed(obj)); // true
Object.keys()
返回对象自身可枚举属性组成的数组,属性名属性与for…in 循环遍历的顺序一致。
let arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // ['0', '1', '2'];
let obj = {0: 'a', 1: 'b', 2: 'c'};
console.log(Object.keys(obj)); // ['0', '1', '2'];
let anObj = {100: 'a', 2: 'b', 7: 'c'};
console.log(Object.keys(anObj)); // ['100', '2', '7']
let myObj = Object.create({}, {
getFoo: {
value: function() {
return this.foo;
}
}
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // ['foo']
Object.values()
【不支持ie】
返回一个给定对象自身的所有可枚举属性值的数组
与for…in 循环遍历该对象时返回顺序一致,但 for…in 循环还会枚举原型链中的属性
let valObj = {foo: 'bar', baz: 42};
console.log(Object.values(valObj)); // ['bar', 42]
console.log(Object.values('foo')); // ['f', 'o', 'o']
Object.entries()
【不支持Ie】
返回一个给定对象自身可枚举属性的键值对数组
与for…in 循环遍历该对象时返回顺序一致,但for…in 循环还会枚举原型链中的属性。
const obj = {foo: 'bar', baz: 42};
console.log(Object.entries(obj));
// 对象转map
let mapObj = new Map(Object.entries(obj));
console.log(mapObj);