【对象的扩展】
属性的简洁表示法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
1 2 3 4 5 6
| const foo = 'bar'; const baz = {foo}; baz
const baz = {foo: foo};
|
上面代码中,变量foo
直接写在大括号里面。这时,属性名就是变量名, 属性值就是变量值。下面是另一个例子。
1 2 3 4 5 6 7 8 9 10 11
| function f(x, y) { return {x, y}; }
function f(x, y) { return {x: x, y: y}; }
f(1, 2)
|
除了属性简写,方法也可以简写。
1 2 3 4 5 6 7 8 9 10 11 12 13
| const o = { method() { return "Hello!"; } };
const o = { method: function() { return "Hello!"; } };
|
下面是一个实际的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13
| let birth = '2000/01/01';
const Person = {
name: '张三',
birth,
hello() { console.log('我的名字是', this.name); }
};
|
这种写法用于函数的返回值,将会非常方便。
1 2 3 4 5 6 7 8
| function getPoint() { const x = 1; const y = 10; return {x, y}; }
getPoint()
|
方括号语法
方括号语法的用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const prop = 'age'; const person = {}; person.prop = 18; console.log(person);
const prop = 'age'; const person = {}; person[prop] = 18; console.log(person);
const prop = 'age'; const person = { [prop]: 18 }; console.log(person);
|
方括号中可以放什么
1 2 3 4 5 6 7 8 9 10
| const prop = 'age'; const func = () => 'age2'; const person = { [prop]: 18, [func()]: 24, ['sex']: 'man', ['s' + 'ex2']: 'womam' }; console.log(person);
|
注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
,这一点要特别小心。
1 2 3 4 5 6 7 8 9
| const keyA = {a: 1}; const keyB = {b: 2};
const myObject = { [keyA]: 'valueA', [keyB]: 'valueB' };
myObject
|
上面代码中,[keyA]
和[keyB]
得到的都是[object Object]
,所以[keyB]
会把[keyA]
覆盖掉,而myObject
最后只有一个[object Object]
属性。
方括号语法和点语法的区别
- 点语法是方括号语法的特殊形式
- 属性名由数字、字母、下划线以及 $ 构成,并且数字还不能打头的时候可以使用点语法(合法标识符)
- 能用点语法优先使用点语法
1 2 3 4 5
| const person = { age: 18 };
person.age 等价于 person['age']
|
super 关键字
我们知道,this
关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super
,指向当前对象的原型对象。
1 2 3 4 5 6 7 8 9 10 11 12 13
| const proto = { foo: 'hello' };
const obj = { foo: 'world', find() { return super.foo; } };
Object.setPrototypeOf(obj, proto); obj.find()
|
上面代码中,对象obj.find()
方法之中,通过super.foo
引用了原型对象proto
的foo
属性。
注意,super
关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const obj = { foo: super.foo }
const obj = { foo: () => super.foo }
const obj = { foo: function () { return super.foo } }
|
上面三种super
的用法都会报错,因为对于 JavaScript 引擎来说,这里的super
都没有用在对象的方法之中。第一种写法是super
用在属性里面,第二种和第三种写法是super
用在一个函数里面,然后赋值给foo
属性。目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。
JavaScript 引擎内部,super.foo
等同于Object.getPrototypeOf(this).foo
(属性)或Object.getPrototypeOf(this).foo.call(this)
(方法)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const proto = { x: 'hello', foo() { console.log(this.x); }, };
const obj = { x: 'world', foo() { super.foo(); } }
Object.setPrototypeOf(obj, proto);
obj.foo()
|
上面代码中,super.foo
指向原型对象proto
的foo
方法,但是绑定的this
却还是当前对象obj
,因此输出的就是world
。
对象的展开运算符
展开对象
对象不能直接展开,必须在 {} 中展开。
1 2 3 4 5 6 7
| const apple = { color: '红色', shape: '球形', taste: '甜' }; console.log({...apple}); console.log({...apple} === apple);
|
合并对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const apple = { color: '红色', shape: '球形', taste: '甜' };
const pen = { color: '黑色', shape: '圆柱形', use: '写字' };
console.log({...apple, ...pen}); console.log({...pen, ...apple});
|
注意事项
空对象的展开
如果展开一个空对象,则没有任何效果。
1 2
| console.log({...{}}); console.log({...{}, a: 1});
|
非对象的展开
如果展开的不是对象,则会自动将其转为对象,再将其属性罗列出来(没有属性便为空)。
1 2 3 4 5
| console.log({...1}); console.log(new Object(1)); console.log({...undefined}); console.log({...null}); console.log({...true});
|
字符串的展开
如果展开运算符后面是字符串,它会自动转成一个类似数组的对象,因此返回的不是空对象。
1 2 3 4 5 6 7 8
| console.log({...'alex'});
console.log([...'alex']);
console.log(...'alex');
|
数组的展开
1
| console.log({...[1, 2, 3]});
|
对象中对象属性的展开
不会展开对象中的对象属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const apple = { feature: { taste: '甜' } };
const pen = { feature: { color: '黑色', shape: '圆柱形' }, use: '写字' };
console.log({...apple});
console.log({...apple, ...pen});
|
对象展开运算符的应用
复制对象
1 2 3 4
| const a = {x: 1, y: 2}; const c = {...a}; console.log(c, c === a);
|
用户参数和默认参数
1 2 3 4 5 6 7 8 9 10 11 12
| const logUser = userParam => { const defaultPeram = { username: 'ZhangSan', age: 0, sex: 'male' };
const param = {...defaultPeram, ...userParam}; console.log(param.username, param.age, param.sex); };
logUser({username: 'jerry'});
|
再优化:
1 2 3 4 5 6 7 8 9 10 11 12
| const logUser = userParam => { const defaultPeram = { username: 'ZhangSan', age: 0, sex: 'male' };
const {username, age, sex} = {...defaultPeram, ...userParam}; console.log(username, age, sex); };
logUser({username: 'jerry'});
|
对象的新增方法
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身,以及+0
等于-0
。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
1 2 3 4
| Object.is('foo', 'foo')
Object.is({}, {})
|
不同之处只有两个:一是+0
不等于-0
,二是NaN
等于自身。
1 2 3 4 5
| +0 === -0 NaN === NaN
Object.is(+0, -0) Object.is(NaN, NaN)
|
Object.assign()
Object.assign()
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
1 2 3 4 5 6 7
| const target = { a: 1 };
const source1 = { b: 2 }; const source2 = { c: 3 };
Object.assign(target, source1, source2); target
|
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
1 2 3 4 5 6 7
| const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 }; const source2 = { c: 3 };
Object.assign(target, source1, source2); target
|
汇总
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
const apple = { color: '红色', shape: '圆形', taste: '甜' }; const pen = { color: '黑色', shape: '圆柱形', use: '写字' }; console.log(Object.assign(apple, pen));
console.log(apple); console.log(Object.assign(apple, pen) === apple);
console.log(Object.assign({}, apple, pen)); console.log(apple); console.log({...apple, ...pen});
console.log(Object.assign({}, undefined)); console.log(Object.assign({}, null)); console.log(Object.assign({}, 1)); console.log(Object.assign({}, true)); console.log(Object.assign({}, 'str'));
const apple = { color: ['红色', '黄色'], shape: '圆形', taste: '甜' }; const pen = { color: ['黑色', '银色'], shape: '圆柱形', use: '写字' }; console.log(Object.assign({}, apple, pen));
const logUser = userOptions => { const DEFAULTS = { username: 'ZhangSan', age: 0, sex: 'male' };
const options = Object.assign({}, DEFAULTS, userOptions); console.log(options); }; logUser(); logUser({}); logUser({username: 'Alex'});
|
Object.keys()、Object.values() 和 Object.entries()
Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
Object.values
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
Object.entries()
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| const person = { name: 'Alex', age: 18 };
console.log(Object.keys(person));
console.log(Object.values(person));
console.log(Object.entries(person));
console.log([1, 2].keys()); console.log([1, 2].values()); console.log([1, 2].entries());
const person = { name: 'Alex', age: 18 }; for (const key of Object.keys(person)) { console.log(key); }
for (const value of Object.values(person)) { console.log(value); }
for (const entries of Object.entries(person)) { console.log(entries); }
for (const [key, value] of Object.entries(person)) { console.log(key, value); }
|
数组的扩展
字符串的扩展