一、对象属性的简洁写法
1、属性简写
var foo = "bar";
var baz = { foo };
baz; // { foo: "baz" }
// 等价于
var baz = { foo: foo };
function f(x, y) {
return { x, y };
// 等价于: return { x: x, y: y };
}
f(1, 2); // {x: 1, y: 2}
2、方法简写
var obj = {
method() {
return "yuan is an animal";
}
}
// 等价于
var obj = {
method: function() {
return "yuan is an animal";
}
}
二、属性名表达式
在ES5中,定义对象的属性有两种方法
// 方法一:标识符作为属性名
obj.foo = true;
// 方法二:表达式作为属性名
obj["foo"] = true;
如果使用字面量方式定义对象,在ES5中只能使用方法一,而在ES6中可以使用方法二:
let yuan = "monkey";
let animal = {
"type": "animal",
[yuan]: "yuan is not monkey"
}
animal["type"]; // "animal"
animal[yuan]; // "yuan is not monkey"
animal["monkey"]; // "yuan is not monkey"
属性名定义方法:
let monkey = {
['yuan']() {
return "yuan is a monkey";
}
}
monkey.yuan(); // yuan is a monkey"
三、方法的name 属性
对象中的方法,也具有类似 function 的 name 属性:
let monkey = {
['yuan']() {
return "yuan is a monkey";
}
}
monkey.yuan.name; // "yuan"
其他的用法同“ES6函数扩展”的 name 属性用法类似。
四、Object.is()
因在ES5中,并不能处理比较两个值是否严格相等,对于NaN,+0,-0等并不能做出严格相等来判断。
Object.is() 这个方法就是来弥补上述的缺陷的:
+0 === -0; // true
NaN === NaN; // false
Object.is(+0, -0); // false
Object.is(NaN, NaN); // true
五、Object.assign()
1、基本用法
定义:将源对象(sourceN,不知一个源对象)的所有可枚举属性复制到目标对象上(target)。
使用方式:Object.assign(target, source1, source2, ..., sourceN)
let target = { x: 1};
let s1 = { y: 2 };
let s2 = { z: 3 };
Object.assign(target, s1, s2); // {x: 1, y: 2, z: 3}
2、注意点
(1)、如果目标对象与源对象用同名属性,或多个源对象具有同名属性,则后面的属性会覆盖前面的属性:
let target2 = { x: 1};
let s3 = { x: 3, y: 2 };
let s4 = { y: 4, z: 3 };
Object.assign(target2, s3, s4); // {x: 3, y: 4, z: 3}
(2)如果参数不是对象,则会先转成对象,在返回:
typeof Object.assign(3); // "object"
(3)、若参数中有undefined 或者 null,这两个参数不能放在目标对象的位置,否则会报错:
Object.assign(undefined); // Cannot convert undefined or null to object at Function.assign (<anonymous>)
Object.assign(null); // Cannot convert undefined or null to object at Function.assign (<anonymous>)
(4)、除了字符串会以数组的形式复制到目标对象上,其他值都不会产生效果:
let a1 = 'yuan';
let a2 = true;
let a3 = 11;
let a4 = NaN;
Object.assign({}, a1, a2, a3, a4); // {0: "y", 1: "u", 2: "a", 3: "n"}
(5)、Object.assign()这个方法是对对象引用的复制,即是浅复制,而不是深复制。这里需要规避同名属性替换带来的问题:
var obj1 = { a: { b: 3, c: 4 } };
var obj2 = { a: { b: "yuan" } } ;
Object.assign(obj1, obj2); // { a: { b: "yuan" } }
obj1.a.b; // "yuan"
3、基本用途
(1)、给对象添加属性
class Geo {
constructor(x, y) {
Object.assign(this, x, y);
}
}
(2)、给对象添加方法
Object.assig(SomeClass.prototype, {
someMethod(arg1, arg2) { ... },
anotherMethod() { ... }
})
(3)、克隆对象
function clone(originObj) {
return Object.assign({}, originObj); // 将原始对象复制给空对象
}
(4)、合并多个对象
const mergeObjs = {
(target, ...sources) => Object.assign(target, ...sources);
}
(5)、为属性指定默认值
const DEFAULTS = {
logleve: 0,
outputFormat: 'html'
};
function processContent(options) {
retrun Object.assign({}, DEFAULTS, options);
}
六、属性的可枚举性(Enumerable)
ES5 中有3个操作会忽略 Enumerable 为 false 的属性:
1、for...in 循环:只遍历对象自身的和继承的可枚举性。
2、Object.keys():返回对象自身的所有可枚举属性的键名。
3、JSON.stringify():只串行化对象自身的可枚举属性。
在ES6 中,Object.assign() 操作会忽略 Enumerable 为false 的属性。
在上面四个操作中,只有 for...in 操作会返回继承的属性,为了不使问题复杂化,只关心对象自身的属性。所以,尽量不要使用 for...in 循环,用 Object.keys() 代替。
ES6还规定,所有 Class 的原型的方法都是不可枚举的。
七、属性的遍历
在ES6 中有五种方法来遍历对象的属性:
1、for...in
返回对象自身的和继承的可枚举属性(不含 Symbol 属性)。
2、Object.keys(ob)
返回一个数组,包括对象自身的(不含继承)所有可枚举属性(不含 Symbol 属性)。
3、Object.getOwnPropertyNames(obj)
返回一个数组,包括自身的所有属性(不含Symbol属性,但包括不可枚举属性)。
4、Object.getOwnPropertySymbols(obj)
返回一个数组。包含对象自身的所有 Symbol 属性。
5、Object.ownKeys(obj)
返回一个数组,包含对象所有的属性.。
以上五种方法都遵循同样的遍历顺序:
(1)、首先遍历所有属性名为数值的属性,按数字排序;
(2)、其次遍历所有属性名为字符串的属性,按照生成时间排序;
(3)、最后遍历所有属性名为 Symbol 的属性,按照生成时间排序。
八、Object.keys(),Object.values(),Object.entries()
1、Object.keys(obj)
返回一个数组,是由参数对象自身的(不含继承)所有可遍历属性的键名:
/* Array 对象 */
let arr = ["a", "b", "c"];
console.log(Object.keys(arr));
// ['0', '1', '2']
/* Object 对象 */
let obj = { foo: "bar", baz: 42 },
keys = Object.keys(obj);
// CCAC: Chrome Console Auto Copy
copy(keys);
// ["foo","baz"]
/* 类数组 对象 */
let obj = { 0 : "a", 1 : "b", 2 : "c"};
console.log(Object.keys(obj));
// ['0', '1', '2']
// 类数组 对象, 随机 key 排序 (遵循上述的属性的遍历顺序)
let anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj));
// ['2', '7', '100']
/* getFoo 是个不可枚举的属性 */
var my_obj = Object.create(
{},
{ getFoo : { value : function () { return this.foo } } }
);
my_obj.foo = 1;
console.log(Object.keys(my_obj));
// ['foo']
2、Object.values(obj)
返回一个数组,是由参数对象自身的(不含继承)所有可遍历属性的键值:
var obj = { foo: "bar", baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]
// 类数组对象
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']
// 随机键值的类数组对象 (遵循上述的属性的遍历顺序)
var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj)); // ['b', 'c', 'a']
// getFoo 是不可枚举属性
var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = "bar";
console.log(Object.values(my_obj)); // ['bar']
// 参数是非对象会转变成对象
console.log(Object.values("foo")); // ['f', 'o', 'o']
Object.values() 会过滤属性名为 Symbol 值的属性:
Object.values({ [Symbol() ]: 123, "foo": "faa"}) // ["faa"]
3、Object.entries(obj)
返回一个数组,是由参数对象自身的(不含继承)所有可遍历属性的键值对数组:
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// 类数组对象
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// 随机键值的类数组对象 (遵循上述的属性的遍历顺序)
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
// getFoo 是不可枚举属性
const myObj = Object.create({}, { getFoo: { value() { return this.foo; } } });
myObj.foo = 'bar';
console.log(Object.entries(myObj)); // [ ['foo', 'bar'] ]
// 参数是非对象会转变成对象
console.log(Object.entries('foo')); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]
// 优雅地遍历键值
const obj = { a: 5, b: 7, c: 9 };
for (const [key, value] of Object.entries(obj)) {
console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
}
Object.entries() 的另一个用处:将对象转为真正的Map 数据结构:
var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
结语:
1、本章重点在理解Object.keys(),Object.values(),Object.entries() 三个方法的使用以及Object.assign 的用法
2、属性在ES6中属性的简写与属性名的表达式
3、了解ES6中五种遍历属性的方法及其区别
章节目录
1、ES6中啥是块级作用域?运用在哪些地方?
2、ES6中使用解构赋值能带给我们什么?
3、ES6字符串扩展增加了哪些?
4、ES6对正则做了哪些扩展?
5、ES6数值多了哪些扩展?
6、ES6函数扩展(箭头函数)
7、ES6 数组给我们带来哪些操作便利?
8、ES6 对象扩展
9、Symbol 数据类型在 ES6 中起什么作用?
10、Map 和 Set 两数据结构在ES6的作用
11、ES6 中的Proxy 和 Reflect 到底是什么鬼?
12、从 Promise 开始踏入异步操作之旅
13、ES6 迭代器(Iterator)和 for...of循环使用方法
14、ES6 异步进阶第二步:Generator 函数
15、JavaScript 异步操作进阶第三步:async 函数
16、ES6 构造函数语法糖:class 类