作为一个前端开发工程师,面试中经常会碰到对象的新特性这个问题。面试官们一问“对象新增了哪些扩展?”这还真是能把不少人难倒。
其实呢,ES6以来,JavaScript对象确实新增了很多特性,既提升了代码的可读性,也让开发过程更加便捷。下面我就来详细梳理一下这些新特性,外加一些代码例子,大家可以随手复制粘贴到控制台里运行一下,看看效果。
首先,我们来说说属性的简写。在ES6中,当对象的键名和对应的变量名一样时,可以直接省略赋值。以前我们可能会这样写:
const foo = 'bar';
const baz = { foo: foo };
但在ES6中,这可以简写成:
const foo = 'bar';
const baz = { foo };
不仅是属性,方法也可以简写。如果我们有一个对象需要定义方法,以前的写法是这样:
const o = {
method: function() {
return "Hello!";
}
};
在ES6中,可以这样写:
const o = {
method() {
return "Hello!";
}
};
简洁很多吧?不过这里要注意一点,简写的对象方法不能用作构造函数,否则会报错。试试下面的代码:
const obj = {
f() {
this.foo = 'bar';
}
};
new obj.f(); // 报错
再来说一个有意思的功能属性名表达式。在ES6之前,对象的属性名是固定的字符串,动态生成非常麻烦。但ES6允许在对象定义中直接使用表达式作为属性名。比如:
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
console.log(a['first word']); // "hello"
console.log(a[lastWord]); // "world"
console.log(a['last word']); // "world"
这样我们就可以灵活定义属性名。另外,方法名同样可以是表达式。比如:
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
console.log(obj.hello()); // "hi"
不过要注意,如果尝试同时使用属性名表达式和简洁表示法会报错。正确用法如下:
const foo = 'bar';
const baz = { [foo]: 'abc' }; // 正确
接下来是super关键字。这个关键字之前只在类中见过,现在也可以用于对象字面量,指向对象的原型。来看一个例子:
const proto = { foo: 'hello' };
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
console.log(obj.find()); // "hello"
这个代码段中的super
指向proto
对象。这样,obj.find()
返回的就是proto
的foo
属性。
扩展运算符在对象中也是一项极大的提升。扩展运算符...
可以用来解构赋值,提取对象中的剩余属性,非常实用。举个例子:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
注意一点,扩展运算符用在解构赋值时必须是最后一个参数,否则会报错。另外,扩展运算符是浅拷贝。如果有嵌套对象,修改原对象中的嵌套属性,解构出来的新对象也会受到影响。
再来看看对象的遍历方法。ES6中有五种常用的属性遍历方式:
for...in
:遍历对象的可枚举属性(包括继承属性)。Object.keys(obj)
:返回对象自身的可枚举属性键名(不包括继承属性)。Object.getOwnPropertyNames(obj)
:返回对象自身的所有属性(包括不可枚举属性)。Object.getOwnPropertySymbols(obj)
:返回对象自身的所有Symbol属性。Reflect.ownKeys(obj)
:返回对象自身的所有键名(包括不可枚举和Symbol)。
看个例子:
console.log(Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }));
// 输出顺序是 ['2', '10', 'b', 'a', Symbol()]
这个顺序规则是:数值键按升序,字符串键按添加顺序,Symbol键按添加顺序。
最后,我们来说说ES6新增的对象方法:
Object.is()
严格判断两个值是否相等,特别之处是+0
不等于-0
,但NaN
等于NaN
:
console.log(Object.is(+0, -0)); // false
console.log(Object.is(NaN, NaN)); // true
Object.assign()
用于对象的合并,将源对象的属性复制到目标对象。遇到同名属性会替换。注意,Object.assign()
是浅拷贝:
const target = { a: 1, b: 1 };
const source = { b: 2, c: 3 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 2, c: 3 }
Object.getOwnPropertyDescriptors()
获取对象的所有属性描述信息。这个方法常用在深拷贝等场景:
const obj = {
foo: 123,
get bar() { return 'abc'; }
};
console.log(Object.getOwnPropertyDescriptors(obj));
Object.setPrototypeOf() 和 Object.getPrototypeOf()
Object.setPrototypeOf
用来设置对象的原型,Object.getPrototypeOf
用来读取对象的原型:
const o = Object.setPrototypeOf({}, null);
console.log(Object.getPrototypeOf(o)); // null
Object.keys()、Object.values()、Object.entries()
这些方法分别用于获取对象的键名、键值和键值对数组:
const obj = { foo: 'bar', baz: 42 };
console.log(Object.keys(obj)); // ["foo", "baz"]
console.log(Object.values(obj)); // ["bar", 42]
console.log(Object.entries(obj)); // [["foo", "bar"], ["baz", 42]]
Object.fromEntries()
用于将键值对数组转为对象。这个方法通常和Object.entries()
搭配使用,特别在Map对象的处理上非常方便:
const entries = [['foo', 'bar'], ['baz', 42]];
console.log(Object.fromEntries(entries)); // { foo: "bar", baz: 42 }
综上所述,如果面试官问起“对象新增了哪些扩展?”可以这样回答:
ES6引入了一系列新特性来增强对象的功能,比如属性和方法的简写、属性名表达式、super关键字、扩展运算符等。另外,还增加了许多遍历对象属性的新方法,比如Object.keys、Object.values和Object.entries。同时,像Object.assign、Object.is、Object.getOwnPropertyDescriptors、Object.setPrototypeOf和Object.fromEntries这些方法也让对象的操作更加灵活高效。
目前,对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥私藏精品 热门推荐 虎哥作为一名老码农,整理了全网最全《前端资料合集》。