可以直接写入变量和函数作为对象的属性和方法。在对象中只写属性名,不写属性值,代表属性值等于和属性名相同的的变量的值。
属性的简写
let foo = 'bar';
let baz = {foo}; // { foo: 'bar' }
// 等同于
let baz = { foo: foo}
方法的简写
let o = {
method: function() {
return 'hello';
}
}
let o = {
method() {
return 'hello';
}
}
好处:
如果某个方法的值是一个Generator函数,则前面需要加上星号。
const obj = {
* m() {
yield 'hello world';
}
}
在js之前对象定义属性名可以使用标识符或者表达式。但是如果使用字面量定义对象(大括号),只能使用标识符定义,不能使用表达式。
之前写法
// 标识符定义
obj.foo = true;
// 表达式定义
obj['a'+ 'b'] = 123;
在ES6中在定义对象时表达式可以定义属性名、方法名。
但是属性名表达式不能与简洁表示法一起使用,否则会报错。
// 定义在对象中
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'b']: 123,
}
// 定义在方法
let a = {
'first word': 'hello',
['a'+'b'](){
return 'hi';
}
}
// 不能与简洁表示法一块使用
let foo = 'bar';
let baz = { [foo] }; // 会报错
// 可以这样写
let baz = { [foo]: foo }
注意:如果属性表达式是一个对象,默认情况下会自动转为字符串[object Object],这样就要特别注意!
const keyA = { a: 1};
const keyB = { b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB',
}
console.log(myObject); // [object Object]: 'valueB'
这是因为这两个属性名都是对象,都转成同一个属性名[object Object]
,所以就把上面的属性自动覆盖掉了,不能有相同名称的属性名。
函数的name属性返回函数名,方法也是函数,也有name属性并返回函数名即方法名。
const person = {
sayName() {
console.log('hello');
}
}
person.sayName.name // 'sayName'
对于方法使用了get、set函数,则name属性不在该方法上。则在方法属性的描述对象的get和set属性上,返回值会在方法名前加上get和set。
如何操作获取含有get、set的方法名?
Object.getOwnPropertyDescriptor()
方法,获取该属性的描述对象。const obj = {
get foo() {},
set foo(x) {}
}
obj.foo.name; // 会报错
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name; // 'get foo'
descriptor.set.name; // 'get foo'
特殊情况!bind方法创造的函数,name属性返回值会在函数名的前面加上bound
;Function构造函数创造的函数,name属性返回anonymous
。
(new Function()).name // 'anonymous'
const doSomething = function(){}
doSomething.bind().name // 'bound doSomething'
如果对象的方法是一个Symbol
值,那么属性返回的是这个Symbol值的描述。
用来比较两个值是否严格相等,与严格相等运算符(===)的行为一致。返回布尔类型
两个不同的是,+0不等于-0,NaN等于自身
Object.is('foo', 'foo'); // true
Object.is(NaN, NaN); // true
Object.is(+0, -0); // false
为什么ES6要提供Object.is方法?
因为在ES5中比较两个值是否相等,只有相等运算符()和严格相等运算符(=)两种,但他们有个缺点,前者在比较时会自动转换数据类型,后者在比较时,NaN不等于自身,+0等于-0,造成js中缺少一种运算,就是在所有环境中,只要两个值是一样的,它们就应该相等。所有在ES6中提出了Same-value equality
(同值相等)算法来解决这个问题。
如何在ES5中模拟Object.is
Object.defineProperty(Object, 'is', {
value: function(x, y) {
if(x === y) {
// 针对+0 不等于-0的情况
return x !== 0 || 1 / x === 1 /y;
}
// 针对NaN的情况
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true
})
用于将源对象的所有可枚举属性复制到目标对象。
第一个参数:目标对象。后面的参数都是源对象,后面的参数可以为多个。
let target = { a: 1};
let source1 = { b: 2};
let source2 = { c: 3};
Object.assign(target, source1, source2);
target // { a: 1, b: 2, c: 3 }
注意点
typeof Object.assign(2); // 'object'
Object.assign(undefined); // 报错
let obj = {a: 1};
Object.assign(obj, undefined) === obj; // true
const obj = Object.assign({}, 12, true, 'ab'); // {'0': 'a', '1': 'b'}
可以看出转成对象后,它们的原始值都会包装在对象的内部属性[[PrimitiveValue]]上面,这个属性是不会被Object.assign复制的。只有字符串的包装对象会产生可枚举的实义属性,才会被拷贝
Object.assign({a: 'b'}, {[Symbol('c')]: 'd'});
// { a: 'b', Symbol(c): 'd'}
用途
把一个原始对象复制到一个空对象中
对象的每一个属性都具有一个描述对象,用来控制属性的行为,使用Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj);
/**
{
value: 123,
writable: true,
enumerable: true,
configurable: true
}
*/
enumerable
属性称为可枚举性,若属性值为true,则可以枚举,为false则不能,遍历时会忽略。
会忽略enumerable为false属性的操作,在ES5中有3个,ES6又新增了一个。
共有5中方法
只遍历对象自身和继承过来的可枚举属性
返回一个数组,包括对象自身可枚举属性的键名