属性
访问属性
示例:
let author = {
"first name": "Tonny",
"last-name": "Michael",
age: 40,
};
console.log(author["first name"], author["last-name"]);
let { "first name": fname, "last-name": lname } = author;
console.log(fname, lname, author.age);
作为关联数组的对象
let result = {
data1: {
name: "Language",
value: "Chinese",
},
data2: {
name: "Country",
value: "China",
},
data3: {
name: "Gender",
value: "Male",
},
};
for (let i = 1; i < 4; i++) {
let data = result["data" + i];
console.log(`${data.name}-->${data.value}`);
}
继承
let a = {};
a.x = 1;
let b = inherit(a);
b.y = 2;
let c = inherit(b);
c.z = 3;
console.log(c.toString());
console.log(c.x + c.y + c.z);
属性访问错误
查询一个不存在的属性并不会报错,如果在对象o自身的属性或继承的属性中均未找到属性x,属性访问表达式o.x返回undefined。
但是,如果对象不存在,那么试图查询这个不存在的对象的属性就会报错
示例:
let one = {};
// let one = { two: { three: 3 } };
console.log(one.two.three);
if (one) {
if (one.two) {
if (one.two.three) console.log(one.two.three);
}
}
console.log(one && one.two && one.two.three);
console.log(one?.two?.three); // Null传导运算符
在这些场景下给对象o设置属性p会失败:
o中的属性p是只读的:不能给只读属性重新赋值(defineProperty()方法中有一个例外,可以对可配置的只读属性重新赋值)。
o中的属性p是继承属性,且它是只读的:不能通过同名自有属性覆盖只读的继承属性。
o中不存在自有属性p:o没有使用setter方法继承属性p,并且o的可扩展性(extensible attribute)是false。如果o中不存在p,而且没有setter方法可供调用,则p一定会添加至o中。但如果o不是可扩展的,那么在o中不能定义新属性
删除属性
delete运算符可以删除对象的属性。
它的操作数应当是一个属性访问表达式
delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。
let auth = book.author;
delete book.author;
console.log(book, auth);
delete运算符只能删除自有属性,不能删除继承属性。
要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象。
let o = { x: 1 };
delete o.x;
delete o.toString;
console.log(o, o.toString());
delete不能删除那些可配置性为false的属性。
某些内置对象的属性是不可配置的,比如通过变量声明和函数声明创建的全局对象的属性。
检测属性
判断某个属性是否存在于某个对象中,可以通过in运算符、hasOwnPreperty()和propertyIsEnumerable()方法,甚至也可以仅通过属性查询。
let o = { x: 1 };
console.log("x" in o);
console.log("y" in o);
console.log("toString" in o);
console.log(o.hasOwnProperty("x"));
console.log(o.hasOwnProperty("y"));
console.log(o.hasOwnProperty("toString"));
console.log(o.propertyIsEnumerable("x"));
console.log(o.propertyIsEnumerable("y"));
console.log(o.propertyIsEnumerable("toString"));
console.log(Object.prototype.propertyIsEnumerable("toString"));
枚举属性
for/in循环可以在循环体中遍历对象中所有可枚举的属性(包括自有属性和继承的属性),把属性名称赋值给循环变量。
对象继承的内置方法不可枚举的,但在代码中给对象添加的属性都是可枚举的。
let o =Object.create({m:10,n:20});
o.x=1; o.y=2; o.z=3;
for (let p in o) {
console.log(p, o[p]);
}
利用for/in循环,可以对两个对象进行各种形式的合并。
Object.keys(),它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。
let o = Object.create({ m: 10, n: 20 });
o.x = 1; o.y = 2; o.z = 3;
console.log(Object.keys(o));
Object.getOwnPropertyNames(),它和Ojbect.keys()类似,只是它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性。
let o = Object.create({ m: 10, n: 20 });
o.x = 1; o.y = 2; o.z = 3;
console.log(Object.getOwnPropertyNames(o));
属性的特性
除了包含名字和值之外,属性还包含一些标识它们可写、可枚举和可配置的特性。
可以通过这些API给原型对象添加方法,并将它们设置成不可枚举的,这让它们看起来更像内置方法。
可以通过这些API给对象定义不能修改或删除的属性,借此“锁定”这个对象。
数据属性的4个特性
值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)。
存取器属性不具有值(value)特性和可写性。
它们的可写性是由setter方法存在与否决定的。
因此存取器属性的4个特性是读取(get)、写入(set)、可枚举性和可配置性。