前言
其实个人一直觉得学习一种新的知识概念,用一道题目引进会更好,这样不仅可以激起你的求知欲,还能带你认识这种机制可能考察的面试场景。可能以前你对他们两有所耳闻,或者轻微的了解,但是它不足以让你去正确的使用它,请大家和我一起走进这道面试题。
面试题
这道题目很简单粗暴,就是给你一段代码,让你判断他会输出什么,往往这种题目都充满了坑,等着你去跳,其实这就是考察你的基本功是否扎实。
下面代码的输出结果是?
const s = '123'
s.c = '4';
s.d = '5';
const [a, b] = s;
const { c, d } = s;
console.log(a, b, c, d);
我们这里不着急知道答案,一步步来分析。首先我们声明了一个常量字符串 s
,它的值为 123
,然后是给 字符串 s
添加了一个属性 c
它的值为 4
。众所周知,在JavaScript中,字符串是一个基本数据类型,他是没有方法和属性的,那是不是这个代码直接就报错了呢?其实他还是可以正常运行的,这归功于JavaScipt提供的装箱机制。
装箱机制
在 JavaScript 中,原始类型(如字符串、数字、布尔值等)是不可变的,并且没有方法或属性。为了方便操作这些原始类型,JavaScript 提供了对应的包装对象(wrapper objects),例如 String
、Number
和 Boolean
。当你尝试调用一个原始类型的属性或方法时,JavaScript 会自动将该原始值“装箱”为相应的包装对象,以便你可以访问这些属性和方法。这就是为什么你可以直接在字符串后面加上
.length直接就可以访问字符串的长度,这个属性了。
const str = 'hello';
console.log(str.length); // 输出: 5
它的过程是str
是一个原始字符串 'hello'
,但它没有 length
这个属性,为了让你能够访问 length
,JavaScript 会在后台临时创建一个 String
包装对象,一旦属性或方法被访问完毕,这个临时的包装对象就会被销毁,原始字符串保持不变。
我们现在知道了当你触发装箱机制的时候,他会创建一个临时的字符串包装对象,然后给他添加上 c 这个属性,值为 4,然后就被销毁了,同理 s.d 也是一样的。所以这两句代码
s.c = '4';
s.d = '5';
写了等于没写,他就是为了迷惑你的,顺便考察你对装箱机制的了解。
解构
我们继续分析代码,发现下面就是我们大名鼎鼎的ES6新增的结构赋值机制。
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring),它允许你从数组或对象中提取数据,并将它们赋值给变量。
这里我们分为数组解构和对象解构来介绍,正好题目也是分别用到了这两种。
数组解构
数组解构允许你从数组中按顺序提取元素,并将它们赋值给变量。你可以选择提取部分元素,也可以跳过某些元素。
基本用法
const arr = [1, 2, 3, 4, 5];
const [a, b, c] = arr;
console.log(a, b, c); // 输出: 1 2 3
在这个例子中,a
、b
和 c
分别被赋值为数组 arr
的前三个元素。
跳过元素
你可以使用逗号来跳过不需要的元素:
const arr = [1, 2, 3, 4, 5];
const [a, , c] = arr;
console.log(a, c); // 输出: 1 3
在这里,b
被跳过,a
和 c
分别被赋值为 1
和 3
。
默认值
如果数组中的某些元素不存在,你可以为变量提供默认值:
const arr = [1, 2];
const [a, b, c = 3] = arr;
console.log(a, b, c); // 输出: 1 2 3
在这里,c
的默认值是 3
,因为数组中没有第三个元素。
嵌套数组解构
你还可以对嵌套的数组进行解构:
const arr = [1, [2, 3], 4];
const [a, [b, c], d] = arr;
console.log(a, b, c, d); // 输出: 1 2 3 4
对象解构
对象解构允许你从对象中提取属性,并将它们赋值给变量。你可以选择提取部分属性,也可以为变量指定不同的名称。
基本用法
const obj = { name: 'Alice', age: 25, city: 'New York' };
const { name, age, city } = obj;
console.log(name, age, city); // 输出: Alice 25 New York
在这个例子中,name
、age
和 city
分别被赋值为对象 obj
中对应的属性值。
提取部分属性
你可以只提取你需要的属性,而忽略其他属性:
const obj = { name: 'Alice', age: 25, city: 'New York' };
const { name, city } = obj;
console.log(name, city); // 输出: Alice New York
重命名变量
你可以通过在解构时指定不同的变量名来重命名提取的属性:
const obj = { name: 'Alice', age: 25, city: 'New York' };
const { name: userName, age: userAge } = obj;
console.log(userName, userAge); // 输出: Alice 25
在这里,name
属性被赋值给 userName
,age
属性被赋值给 userAge
。
默认值
如果对象中某些属性不存在,你可以为变量提供默认值:
const obj = { name: 'Alice' };
const { name, age = 30 } = obj;
console.log(name, age); // 输出: Alice 30
在这里,age
的默认值是 30
,因为对象中没有 age
属性。
嵌套对象解构
你还可以对嵌套的对象进行解构:
const obj = {
user: {
name: 'Alice',
address: {
city: 'New York',
zip: '10001'
}
}
};
const { user: { name, address: { city, zip } } } = obj;
console.log(name, city, zip); // 输出: Alice New York 10001
结果水落石出
其实讲到这里大家心里已经有了答案了, 没错他就是 1 2 undefined undefined 。 这就是因为 他们两的区别 一个是数组解构,一个是对象解构。
- 数组解构:
[a, b] = s
会从字符串'123'
中提取前两个字符,因此a
和b
分别是'1'
和'2'
。 - 对象解构:
{ c, d } = s
试图从s
中提取c
和d
属性。然而,由于s
是一个原始字符串,它并没有c
和d
这些属性。即使你之前尝试给s
添加了这些属性,它们也只存在于那个短暂的包装对象上,而不会保留在原始字符串中。因此,c
和d
都会被赋值为undefined
。
END
到这里恭喜大家,你已经解锁了一道来自 OPPO 的秋招题目,难度不算难,但是很考察你基本功是否扎实,大家是否从中收获了呢,可以在评论区交流,这道题的分享就到这里了。