4. 对象新增了哪些扩展?
一、面试开场怎么答更有条理
如果面试官问:
ES6 对对象新增了哪些扩展?
不要直接开始背 API。
更好的答法是先分类:
ES6 对对象的扩展,我一般会从对象写法简化、属性名表达式、方法扩展、对象合并、属性遍历、原型相关能力、Object 新增静态方法这几个方面来回答。
比较常见的有:属性简写、方法简写、计算属性名、Object.is()、Object.assign()、Object.keys()/values()/entries()、对象的扩展运算符、super、__proto__、Object.setPrototypeOf()/Object.getPrototypeOf()等。
这样一开口就很像“系统理解”,不是机械背诵。
二、ES6 对对象新增了哪些扩展?
1)属性简写
ES6 允许在对象中,属性名和变量名相同的时候直接简写。
ES5 写法
const name = 'Tom' const age = 18 const obj = { name: name, age: age }ES6 写法
const name = 'Tom' const age = 18 const obj = { name, age }作用
- 写法更简洁
- 语义更清晰
- 在返回对象、封装数据时非常常用
面试加分点
属性简写本质上是对象字面量语法增强,特别适合在函数返回对象时使用。
2)方法简写
对象中的函数可以简写。
ES5
const obj = { sayHello: function() { console.log('hello') } }ES6
const obj = { sayHello() { console.log('hello') } }优点
- 更接近类方法语法
- 可读性更强
注意
这种写法定义的是普通函数,不是箭头函数,this依然由调用方式决定。
3)计算属性名
ES6 支持在对象字面量中使用表达式作为属性名。
const key = 'name' const obj = { [key]: 'Tom' } console.log(obj.name) // Tom更复杂的例子
const index = 1 const obj = { ['item' + index]: 'value' } console.log(obj.item1) // value场景
- 动态生成对象 key
- 表单数据映射
- 配置对象构建
面试亮点
计算属性名让对象字面量具备了更强的动态表达能力,这在封装配置对象时很常见。
4)Object.is()
作用
用来比较两个值是否严格相等,行为比===更合理一些。
Object.is(1, 1) // true Object.is('a', 'a') // true它和===的区别
主要区别在两个特殊值上:
+0 === -0 // true Object.is(+0, -0) // false NaN === NaN // false Object.is(NaN, NaN) // true面试加分说法
Object.is()可以理解为“更精确语义的严格相等比较”,尤其解决了NaN和+0/-0的边界问题。
5)Object.assign()
这是 ES6 对对象最重要的扩展之一。
作用
用于将一个或多个源对象的可枚举属性,复制到目标对象上。
const target = { a: 1 } const source = { b: 2 } Object.assign(target, source) console.log(target) // { a: 1, b: 2 }常见用途
(1)对象合并
const obj = Object.assign({}, { a: 1 }, { b: 2 }) console.log(obj) // { a: 1, b: 2 }(2)浅拷贝
const obj1 = { a: 1 } const obj2 = Object.assign({}, obj1)(3)给对象设置默认值
const defaults = { size: 'M', color: 'red' } const config = { color: 'blue' } const result = Object.assign({}, defaults, config) console.log(result) // { size: 'M', color: 'blue' }注意点:它是浅拷贝
const obj1 = { a: { b: 1 } } const obj2 = Object.assign({}, obj1) obj2.a.b = 2 console.log(obj1.a.b) // 2面试亮点
Object.assign()很常用,但一定要说明它是浅拷贝,只会拷贝第一层属性,如果属性值是引用类型,复制的是地址。
这句话几乎必说。
6)对象属性的遍历能力增强
Object.keys()
返回对象自身可枚举属性的键名数组。
const obj = { a: 1, b: 2 } console.log(Object.keys(obj)) // ['a', 'b']Object.values()
返回对象自身可枚举属性的值数组。
const obj = { a: 1, b: 2 } console.log(Object.values(obj)) // [1, 2]Object.entries()
返回对象自身可枚举属性的键值对数组。
const obj = { a: 1, b: 2 } console.log(Object.entries(obj)) // [['a', 1], ['b', 2]]常见用途
转 Map
const obj = { a: 1, b: 2 } const map = new Map(Object.entries(obj))配合for...of
for (const [key, value] of Object.entries(obj)) { console.log(key, value) }面试加分点
Object.entries()很实用,因为它把对象数据转成了更适合迭代处理的二维数组结构。
7)对象的扩展运算符...
虽然对象展开在更严格分类里通常归到 ES2018,但前端面试里经常会和 ES6 一起问,你可以主动说明。
对象合并
const a = { x: 1 } const b = { y: 2 } const c = { ...a, ...b } console.log(c) // { x: 1, y: 2 }对象拷贝
const obj1 = { a: 1 } const obj2 = { ...obj1 }覆盖属性
const obj = { a: 1, b: 2, ...{ b: 3 } } console.log(obj) // { a: 1, b: 3 }面试中怎么说更严谨?
对象扩展运算符非常常用,但它严格来说不是 ES6,而是后续版本加入的。不过工程里常和
Object.assign()一起用于对象浅拷贝和合并。
这样说会显得你很严谨。
8)__proto__与原型操作方法
ES6 明确了获取和设置原型的一些方式。
Object.getPrototypeOf()
获取对象原型
const obj = {} console.log(Object.getPrototypeOf(obj) === Object.prototype) // trueObject.setPrototypeOf()
设置对象原型
const proto = { say() { console.log('hello') } } const obj = {} Object.setPrototypeOf(obj, proto) obj.say() // hello__proto__
const obj = {} console.log(obj.__proto__ === Object.prototype) // true不过一般不推荐在生产中频繁直接操作__proto__,因为可读性和性能都不理想。
面试加分说法
ES6 之后更推荐通过
Object.getPrototypeOf()和Object.setPrototypeOf()操作原型,而不是直接依赖__proto__。
9)对象方法中的super
ES6 允许在对象的方法中使用super,指向当前对象的原型对象。
const proto = { foo() { console.log('proto foo') } } const obj = { foo() { super.foo() } } Object.setPrototypeOf(obj, proto) obj.foo() // proto foo注意
super只能在对象的简写方法中使用,不能在普通函数属性中随便用。
面试亮点
对象中的
super本质上是对原型方法的引用能力增强,它让对象字面量的方法也具备了类似类继承中的调用上层方法能力。
10)属性的可枚举性变化与遍历顺序
这个属于进阶内容,能讲出来会显得很强。
ES6 对对象属性遍历顺序做了更明确的规则:
- 先遍历整数属性名,按升序
- 再遍历字符串属性名,按加入顺序
- 最后遍历 Symbol 属性名,按加入顺序
示例
const obj = { 2: 'b', 1: 'a', c: 'c', b: 'b' } console.log(Object.keys(obj)) // ['1', '2', 'c', 'b']这个属于高级回答,可选补充。
三、面试怎么回答更精彩?
你不能只说“新增了哪些 API”,要再说一句“为什么这些扩展重要”。
可以这样总结:
我觉得 ES6 对对象的扩展,本质上做了三件事:
第一,让对象字面量写法更简洁,比如属性简写、方法简写、计算属性名;
第二,让对象的拷贝、合并和遍历更方便,比如Object.assign()、Object.keys()、Object.values()、Object.entries();
第三,让对象更好地融入原型和面向对象能力,比如super、Object.getPrototypeOf()、Object.setPrototypeOf()。
所以它不只是加了几个 API,而是整体提升了对象在工程中的表达能力。
这段是很加分的总结。
四、标准版面试回答
ES6 对对象主要新增了几类扩展。
第一类是对象字面量增强,比如属性简写、方法简写和计算属性名。它们让对象定义更简洁,也更适合动态构建对象。
第二类是对象静态方法增强,比如
Object.is()和Object.assign()。Object.is()提供了比===更合理的值比较方式,而Object.assign()常用于对象合并和浅拷贝,但要注意它只能做浅拷贝。第三类是对象遍历能力增强,比如
Object.keys()、Object.values()、Object.entries(),尤其Object.entries()很适合配合for...of或转换成Map使用。第四类是原型和继承相关的增强,比如
Object.getPrototypeOf()、Object.setPrototypeOf(),以及对象方法中的super,这些都让对象的原型操作更明确。另外在实际开发中,对象扩展运算符
...也经常和这些内容一起使用,虽然它严格来说属于后续版本,但工程里常用于对象的浅拷贝和合并。如果从整体上看,我觉得 ES6 对对象的扩展,核心是让对象写法更简洁、遍历更方便、原型操作更规范。
五、如果想答得更高级,可以补充这些点
1)Object.assign()和对象展开运算符的共同点
- 都常用于对象合并
- 都是浅拷贝
- 后面的属性会覆盖前面的属性
2)Object.is()和===的区别
重点记住两点:
NaN+0/-0
3)对象字面量方法简写不是箭头函数
这点很多人会混淆,主动提一下很加分。
4)Object.entries()很适合和Map配合
说明你知道它的实际应用价值。
六、对比总结表
| 扩展 | 作用 | 说明 |
|---|---|---|
| 属性简写 | {name} | 属性名和值名相同时简写 |
| 方法简写 | foo() {} | 对象方法定义更简洁 |
| 计算属性名 | [key]: value | 支持动态属性名 |
Object.is() | 更精确的值比较 | 区分+0/-0,识别NaN |
Object.assign() | 对象合并/浅拷贝 | 只拷贝一层 |
Object.keys() | 获取键名数组 | 可枚举属性 |
Object.values() | 获取值数组 | 可枚举属性 |
Object.entries() | 获取键值对数组 | 方便遍历、转Map |
Object.getPrototypeOf() | 获取原型 | 原型操作更规范 |
Object.setPrototypeOf() | 设置原型 | 不建议频繁使用 |
super | 调用原型上的方法 | 用于对象简写方法中 |
... | 对象展开 | 严格来说是后续版本 |
七、精简版面试回答
如果想短一点,可以这样说:
ES6 对对象的扩展主要有三类:
一是对象字面量增强,比如属性简写、方法简写和计算属性名;
二是静态方法增强,比如Object.is()和Object.assign(),其中Object.assign()常用于对象合并和浅拷贝;
三是遍历和原型能力增强,比如Object.keys()、Object.values()、Object.entries(),以及Object.getPrototypeOf()、Object.setPrototypeOf()和对象方法中的super。如果从工程角度看,这些扩展主要让对象的定义更简洁、遍历更方便、合并和原型操作更规范。
八、一句话总结
面试官真正想听的是:
- 你是否知道ES6 对对象新增了哪些能力
- 你能不能按分类进行表达
- 你是否理解这些扩展在实际开发中的价值
- 你会不会主动指出像对象展开运算符这类内容的版本边界
