基本概念
对象是无序属性的集合,其属性值可以是基本数据类型(Boolean、Number、String等),也可以是引用类型(Object、Array、Function等)。对象的每个属性都有一个key(可以理解为属性名),而每个key都映射一个value(值)。
例子:
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Key 键
key拥有4个数据属性和4个访问器属性:
1、 数据属性
[[configurable]]:表示能否通过delete删除属性从而重新定义属性,默认值为true。
[[enumerable]]:表示能否通过for-in循环返回属性,默认值为true。
[[writable]]:表示能否修改属性的值,默认值为true。
[[value]]:该属性的值,默认值为undefined。
要创建或修改key的4个数据属性值,需要使用Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象,属性名和描述符对象。
例子:
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
//使用Object.defineProperty()方法为对象obj创建新属性:age
Object.defineProperty(obj, "age", {
configurable: true,
enumerable: true,
writable: true,
value: 20
})
测试代码:
//测试1:configurable: false
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "age", {
configurable: false,
enumerable: true,
writable: true,
value: 20
})
delete obj.age;
console.log(obj.age);
//输出:20
//说明删除age属性失败
//测试2:enumerable: false
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "age", {
configurable: true,
enumerable: false,
writable: true,
value: 20
})
for (k in obj) {
console.log(k);
}
//输出:name、action
//说明遍历age属性失败
//测试3: writable: false
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "age", {
configurable: true,
enumerable: true,
writable: false,
value: 20
})
obj.age = 18;
console.log(obj.age);
//输出:20
//说明修改age属性失败
注意:
1、使用Object.defineProperty()方法创建的属性,如果不指定configurable、enumerable和writable的值,默认值为false,而用其他方式创建的属性,configurable、enumerable和writable的默认值为true。
测试代码:
*可以使用Object.getOwnPropertyDescriptor()方法读取属性的数据属性和访问器属性。
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "age", {
value: 20
})
console.log(Object.getOwnPropertyDescriptor(obj, "name"));
//输出:{value: "new obj", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj, "age"));
//输出:{value: 20, writable: false, enumerable: false, configurable: false}
2、可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable设置为false之后,再调用Object.defineProperty()方法修改configurable和enumerable,就会导致错误。
测试代码:
//测试1:第二次修改 writable和value
var obj = {
name: "Tom",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "name", {
configurable: false,
enumerable: true,
writable: true,
value: "Amy"
})
Object.defineProperty(obj, "name", {
writable: false,
value: "Lili"
})
console.log(obj.name);
//输出:Lili
//第二次调用Object.defineProperty()方法:writable和value可以正常修改
//测试2:第二次修改 configurable
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "name", {
configurable: false,
enumerable: true,
writable: true,
value: 20
})
Object.defineProperty(obj, "name", {
configurable: true
})
console.log(obj.name);
//输出:error
//测试3:第二次修改 enumerable
var obj = {
name: "new obj",
action: function() {
return this.name
}
}
Object.defineProperty(obj, "name", {
configurable: false,
enumerable: true,
writable: true,
value: 20
})
Object.defineProperty(obj, "name", {
enumerable: false
})
console.log(obj.name);
//输出:error
2、 访问器属性
[[configurable]]:表示能否通过delete删除属性从而重新定义属性,默认值为false。
[[enumerable]]:表示能否通过for-in循环返回属性,默认值为false。
[[getter]]:在读取属性时调用的函数,默认值为undefined。
[[setter]]: 在写入属性时调用的函数,默认值为undefined。
测试代码:
var obj = {
name: "new obj",
_age: 18,
action: function() {
return this.name
}
}
Object.defineProperty(obj, "age", {
configurable: true,
enumerable: true,
get: function() {
return this._age;
},
set: function(newAge) {
return this._age = newAge;
}
})
console.log(obj.age);
obj.age = 20;
console.log(obj.age);
//输出:18、20
注意:
访问器属性只能通过Object.defineProperty()方法定义。
定义多个属性以及数据属性和访问器属性的混合应用
创建或修改多个属性可以使用Object.defineProperties()方法:
测试代码:
var obj = {
name: "Tom",
_year: 2017,
action: function() {
return this.name
}
}
Object.defineProperties(obj, {
name: {
enumerable: false,
value: "Amy"
},
age: {
enumerable: true,
value: 18
},
this_year: {
enumerable: true,
get: function() {
return this._year
},
set: function(num) {
return this._year = num
}
}
})
console.log(obj.name)
//输出:Amy
console.log(obj.age)
//输出:18
console.log(obj._year)
//输出:2017
console.log(obj.this_year)
//输出:2017
for (k in obj) {
console.log(k)
}
//输出:_year、action、age、this_year
obj.this_year = 2018
console.log(obj._year)
//输出:2018
console.log(obj.this_year)
//输出:2018
obj._year = 2018
console.log(obj._year)
//输出:2018
console.log(obj.this_year)
//输出:2018
//修改this_year和_year中任意一个属性的value,可以同时更新this_year和_year的value。
ES5、ES6和ES7常用的对象方法
Object.is()
ES5 比较两个值是否相等,只有两个运算符:相等运算符
(==)
和全等运算符(===)
。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。ES6引入了Object.is()
方法来弥补全等运算符的不准确运算。这个方法接受两个参数,如果这两个参数类型相同且具有相同的值,则返回true。
例子:
let a = [1, 2, 3],
b = a,
c = a;
console.log(Object.is(1, "1")); //输出:false
console.log(Object.is(-0, +0)); //输出:false
console.log(Object.is(NaN, NaN)); //输出:true
console.log(Object.is(b, c)); //输出:true
Object.assign()
Object.assign()方法用于对象的合并,这个方法的第一个参数是目标对象,后面的参数都是源对象,最终结果是返回目标对象。其中源对象的数量是任意的,如果多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的。另外需要注意,Object.assign()方法只拷贝对象自身的可枚举的属性,不可枚举或继承的属性不会拷贝。
例子:
let o1 = {
name: "Tom",
age: 20
},
o2 = Object.create({
//继承的属性不能拷贝
job: "IT"
}, {
//可枚举的属性可以拷贝
"family": {
enumerable: true,
value: "mama"
},
//不可枚举的属性不可拷贝
"school": {
value: "school"
},
//覆盖对象o1的name属性
"name": {
enumerable: true,
value: "Amy"
}
});
let obj = Object.assign({}, o1, o2);
console.log(obj); //输出:{name: "Amy", age: 20, family: "mama"}
利用Object.assign()为对象一次性添加多个方法。
例子:
let obj = {
name: "Tom",
age: 19
}
let objFn = {
fn1() {
console.log(this.name);
},
fn2() {
console.log(this.age);
}
}
Object.assign(obj, objFn);
obj.fn1(); //输出:Tom
obj.fn2(); //输出:19
Object.keys()、Object.values()、Object.entries()
Object.keys() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的属性名。
Object.values() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的属性值。
Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可枚举(enumerable)属性的键值对数组。
例子:
let obj = Object.create({
//继承的属性不能取到
job: "IT"
});
Object.defineProperty(obj, "school", {
//不可枚举的属性不能取到
value: "school"
})
Object.assign(obj, {
//自身属性可以取到
name: "Tom",
age: 19,
//访问器属性可以取到
get family() {
return "mama";
}
})
let objKeys = Object.keys(obj);
let objVals = Object.values(obj);
let objKVls = Object.entries(obj);
console.log(objKeys); //输出:["name", "age", "family"]
console.log(objVals); //输出:["Tom", 19, "mama"]
console.log(objKVls); //输出:[["name", "Tom"], ["age", 19],["family", "mama"]]
上面三个方法涉及到对象属性枚举顺序的问题,ES6的基本规则是:
1、所有数值键按照数值升序排列。
2、所有字符串键按照加入对象的时间顺序排列。
3、所有Symbol键按照加入对象的时间顺序排列(ES6中的新数据类型)。
例子:
let obj = {
a: "a",
0: 0,
c: "c",
2: 2,
}
Object.assign(obj, {
b: "b",
1: 1
});
console.log(Object.keys(obj)); //输出:["0", "1", "2", "a", "c", "b"]
console.log(Object.values(obj)); //输出:[0, 1, 2, "a", "c", "b"]
console.log(Object.entries(obj)); //输出:[ ["0", 0], ["1", 1], ["2", 2], ["a", "a"], ["c", "c"], ["b", "b"]]
for (let k in obj) {
console.log(k); //输出:0, 1, 2, a, c, b
}
文中的代码部分,带有“例子”和“测试代码”字样的,只是用来学习或测试某一功能用的代码,不可以直接用于项目的开发中。带有“代码如下”字样的,都是经过本人测试,简单修改即可用于项目开发中的代码,如有错误,欢迎指出。