ECMAScript Obejct 属性操作API
Object
创建对象
我们有很多种方法创建一个对象,Object.create
, Object.assign
Object.create
//字面量
var o = {};
// 等同于
var o = Object.create(Object.prototype)
// 字面量创建对象,建立属性
var obj = {name: "hello"};
// 等同于
var obj = Object.create(Object.prototype, {
name: {writable:true, configurable:true, value: "hello" }
})
// 构造器创建对象
var Obj = function() {
this.name = "hello";
}
var obj = new Obj;
// 等同于使用Obj的原型链创建
var obj = Object.create(Obj.prototype, {
name: {writable:true, configurable:true, value: "hello" }
})
obj.__proto__ == Obj.prototype // true
Object.assign
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象身上,该方法使用源对象的 [ [ Get ] ] 和目标对象的 [ [ Set ] ],所以它会调用相关 getter 和 setter。因此,它分配属性而不是复制或定义新的属性。
语法
Object.assign(target, ...sources)
测试
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 obj = Object.assign({}, o1, o2, o3);
继承属性和不可枚举属性是不能拷贝的
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 }
对象属性增删改
属性有几个特性:
- configurable : 当且仅当该属性的 configurable 为 true 时,该属性
描述符
才能够被改变,也能够被删除。默认为 false。configurable 特性表示对象的属性是否可以被删除,以及除 writable 特性外的其他特性是否可以被修改。 - enumerable: 当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。
- value : 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
- writable: 当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。
- get:一个给属性提供 getter 的方法,如果没有 getter 则为
undefined
。该方法返回值被用作属性值。默认为 undefined。 - set :一个给属性提供 setter 的方法,如果没有 setter 则为
undefined
。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。
创建属性 Object.defineProperty
var o = {};
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// 数据描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", {
value: 0x9f91102,
get: function() {
return 0xdeadbeef;
}
});
修改属性 Object.defineProperty
如果描述符的 configurable 特性
为false
(即该特性为non-configurable),那么除了 writable
外,其他特性都不能被修改,并且数据和存取描述符也不能相互切换。
var o = {};
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : false
});
Object.defineProperty(o, "a", {enumerable : false}) //TypeError: Cannot redefine property: a
设置多个属性 Object.defineProperties
使用 Object.defineProperties 设置多个属性
var obj = {};
Object.defineProperties(obj, {
"property1": {
value: true,
writable: true
},
"property2": {
value: "Hello",
writable: false
}
// 等等.
});
冻结对象 Object.freeze
Object.freeze() 方法可以冻结一个对象,浅冻结,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
冻结对象的所有自身属性都不可能以任何方式被修改。任何尝试修改该对象的操作都会失败,可能是静默失败,也可能会抛出异常(严格模式中)。
var obj = {name:"hello"}
Object.isFrozen(obj) // false
Object.freeze(obj)
Object.isFrozen(obj) // true
obj.name = "hello2" // 严格模式抛错
obj.name = "hello" // freeze
浅冻结
冻结的属性是不能修改的,但是引用的对象是可以修改的。冻结只是冻结对象的属性
var obj = {
name:"hello",
internal: {
name: "internal"
},
internalFunc: function(){
console.log("internal function")
}
}
Object.freeze(obj)
obj.internal.name = "after freeze"
obj.internalFunc = function() {
console.log("after freeze")
}
console.log(obj.internal.name) // after freeze
obj.internalFunc() // internal function
对象属性遍历
for...in
循环只遍历可枚举属性。像 Array 和 Object 使用内置构造函数所创建的对象都会继承自 Object.prototype 和 String.prototype 的不可枚举属性,例如 String
的
indexOf()
方法或者 Object 的
toString
方法。
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true }
});
for(let key in obj){
console.log(key); // age, name, nick
}
hasOwnProperty
可以使用对象的原型链上的hasOwnProperty
方法判断对象是否具有指定的属性作为自身(不继承)属性。
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true },
sex: {writable:true, configurable:true, value: 'male', enumerable: false}
});
for(let key in obj){
if(obj.hasOwnProperty(key)){
console.log(key); // age
}
}
这里因为 sex 不可枚举,所以在 for…in 中没有遍历出来,如果
obj.hasOwnProperty("sex") // true
getOwnPropertyNames
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组。
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true },
sex: {writable:true, configurable:true, value: 'male', enumerable: false}
});
Object.getOwnPropertyNames(obj) // ["age", "sex"]
Object.key
返回一个由给定对象的自身 可枚举属性 组成的数组
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true },
sex: {writable:true, configurable:true, value: 'male', enumerable: false}
});
Object.keys(obj) // ["age"]
Object.values
返回一个给定对象自己的所有可枚举属性值的数组
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true },
sex: {writable:true, configurable:true, value: 'male', enumerable: false}
});
Object.values(obj) // [27]
getOwnPropertyDescriptor
返回指定对象上一个自有属性对应的属性描述符。
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true },
sex: {writable:true, configurable:true, value: 'male', enumerable: false}
});
Object.getOwnPropertyDescriptor(obj, "name") // undefined
Object.getOwnPropertyDescriptor(obj, "nick") // undefined
Object.getOwnPropertyDescriptor(obj, "age") // {value: 27, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(obj, "sex") // {value: "male", writable: true, enumerable: false, configurable: true}
getOwnPropertyDescriptors
用来获取一个对象的所有自身属性的描述符。
var obj = Object.create({
name: "kk",
nick: "kkj"
}, {
age: {writable:true, configurable:true, value: 27, enumerable: true },
sex: {writable:true, configurable:true, value: 'male', enumerable: false}
});
Object.getOwnPropertyDescriptors(obj)
{
"age": {
"value": 27,
"writable": true,
"enumerable": true,
"configurable": true
},
"sex": {
"value": "male",
"writable": true,
"enumerable": false,
"configurable": true
}
}
原型
getPrototypeOf
返回指定对象的原型
let proto = {};
let obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
isPrototypeOf
isPrototypeOf 和 instanceof operator
是不一样的。在表达式 object instanceof AFunction 中
,检测的是AFunction.prototype
是否在object
的原型链中,而不是检测 AFunction 自身。
let proto = {};
let obj = Object.create(proto);
proto.isPrototypeOf(obj) // ture