Object可以看成类。Object上的静态方法有19个,原型上的方法有11个
var o1 = new Object();
var o2 = new Object(undefined);
var o3 = new Object(null);
console.log(o1);
console.log(o2);
console.log(o3);
Object.assign
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。
String类型和 Symbol 类型的属性都会被拷贝。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError,如果在引发错误之前添加了任何属性,则可以更改target对象。 注意,Object.assign 不会在那些source对象值为 null 或 undefined 的时候抛出错误。
原始类型会被包装为对象
const v1 = "abc";
const v2 = true;
const v3 = 10;
const v4 = Symbol("foo")
const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
拷贝访问器
const obj = {
foo: 1,
get bar() {
return 2;
}
};
let copy = Object.assign({}, obj);
console.log(copy); // { foo: 1, bar: 2 } copy.bar的值来自obj.bar的getter函数的返回值
// 下面这个函数会拷贝所有自有属性的属性描述符
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 默认也会拷贝可枚举的Symbols
Object.getOwnPropertySymbols(source).forEach(sym => {
let descriptor = Object.getOwnPropertyDescriptor(source, sym);
if (descriptor.enumerable) {
descriptors[sym] = descriptor;
}
});
Object.defineProperties(target, descriptors);
});
return target;
}
copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }
配置属性描述符并不能使对象不增加属性,属性描述符是针对于对象的属性的,而封印或者冻结是针对于对象的
Object.create
语法:
Object.create(proto,[propertiesObject])
第二个参数需要用属性描述符对象的方式进行传参,传null或者字符串会报错,传undefined不会报错,传数字或者布尔值不会报错,但是如果传的对象不是属性描述符格式的对象就会报错
Object.defineProperty
Object.defineProperty将属性定义为configurable:false时如果同时定义了value还有writable:true,那后面还可以改变value和writable的值,其他情况下都不能改变属性描述符,configurable一旦设置为false之后就不能够删除该属性
Object.preventExtensions/Object.isExtensible
Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。返回值是原对象的引用,而且原对象已经不能扩展。 Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。返回值是布尔值。 该方法使得目标对象的 [[prototype]] 不可变;任何重新赋值 [[prototype]] 操作都会抛出 TypeError 。这种行为只针对内部的 [[prototype]] 属性, 目标对象的其它属性将保持可变。 一旦将对象变为不可扩展的对象,就再也不能使其可扩展。
Object.seal/Object.isSealed
Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。返回值是原对象的引用,而且原对象已经被封印。 封闭一个对象后,这个对象的原型上的属性仍然继承并且原型上的属性可以更改或者增加属性或者删除属性,但是这个对象的__proto__不能更改指向,也就是说这个对象的原型本身不能更改(因为更改指向需要判断该对象本身是不是可以扩展的(Object.isExtensible))
Object.freeze/Object.isFrozen
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。 其实Object.freeze()就是将对象中的属性的属性描述符变成了不可配置,并且把原来包含有writable属性描述符的属性的writable属性描述符全部变为false,但是原来有getter或者setter函数的属性其实只是被改成了不可配置,但是getter或者setter本身并没有被改变,也就是说冻结一个对象其实有办法属性被更改,不过需要在特殊的设置下
let abc = {}
let a = 1;
Object.defineProperty(abc, 'a', {
get () {
return a;
},
set (value) {
a = value;
},
configurable: true
});
Object.freeze(abc);
console.log(Object.isFrozen(abc)); //true
console.log(abc.a); //1
console.log(Object.getOwnPropertyDescriptor(abc, 'a')); //{enumerable: false, configurable: false, get: ƒ, set: ƒ}
abc.a = 2;
console.log(abc.a); //2