解构赋值
什么是解构赋值
解构赋值是一种 Javascript 的语法特性,它可以让我们从数组或对象中提取数据,并赋值给变量,而不需要使用索引或属性名。
解构赋值的语法有两种形式:
- 数组结构:
var [a, b, c] = array; - 对象解构:
var [x, y, z] = object;
数组解构按照数组元素的顺序,将对应位置的值赋值给变量。 对象解构按照对象属性的名称,将对应属性赋值给变量。
什么是可迭代对象
可迭代对象是指可以被遍历的对象,即可以用 for ... of 循环或 ... 扩展运算符来遍历其元素的对象。可迭代对象必须满足可迭代协议,即具有一个名为 Symbol.iterator 的属性,该属性是一个函数,返回一个可迭代对象。
什么是 Symbol.iterator 属性和迭代器对象
Symbol.iterator 是一个内置的 Symbol 值,它表示一个对象的默认迭代器。
当使用 for ... of 循环或 ... 扩展运算符时,会自动调用该属性对应的函数,获取一个迭代器对象。迭代器对象是一个具有 next() 方法的对象,该方法返回一个包含 value 和 done 两个属性的对象。
value表示当前迭代的值done表示是否完成了迭代 每次调用next()方法,都会返回下一个迭代结果,直到done为true为止,表示迭代结束。
var arr = [1, 2, 3];
const iter = arr[Symbol.iterator]();
console.log(iter); // Object [Array Iterator] {}
console.log(iter.next); // [Function: next]
console.log(iter.next()); // { value: 1, done: false }
console.log(iter.next()); // { value: 2, done: false }
console.log(iter.next()); // { value: 3, done: false }
console.log(iter.next()); // { value: undefined, done: true }
什么是 Object.values 方法和生成器函数
Object.values 方法是一个静态方法,它接受一个对象作为参数,返回一个包含该对象所有可枚举属性值的数组。
生成器函数是一种特殊的函数,它可以使用 function* 声明,并且可以使用 yield 关键字暂停执行并返回中间结果。
生成器函数返回一个生成器对象,它也是一个迭代器对象,可以使用 next() 方法继续执行函数,并获取下一个结果。
如何使用解构赋值
我们可以使用解构赋值来简化代码,提高可读性和效率。
例如:
// 不使用解构赋值
var arr = [1, 2, 3];
var a = arr[0];
var b = arr[1];
var c = arr[2];
// 使用解构赋值
var [a, b, c] = arr;
// 不使用解构赋值
var obj = {x: 10, y: 20, z: 30};
var x = obj.x;
var y = obj.y;
var z = obj.z;
// 使用解构赋值
var {x, y, z} = obj;
我们还可以使用解构赋值来交换变量的值,而不需要使用临时变量。
例如:
// 不使用解构赋值
var a = 1;
var b = 2;
var temp = a;
a = b;
b = temp;
// 使用解构赋值
var a = 1;
var b = 2;
[a, b] = [b, a];
我们还可以使用解构赋值来从函数返回多个值,而不需要使用数组或对象。
例如:
// 不使用解构赋值
function getCoords() {
return [10, 20];
}
var coords = getCoords();
var x = coords[0];
var y = coords[1];
// 使用解构赋值
function getCoords() {
return [10, 20];
}
var [x, y] = getCoords();
解构赋值面试题
面试题要求我们让下面的代码成立,不能更改此行代码:
var [a, b] = { a:1, b: 2 };
这意味着我们需要让右边的对象变成一个可迭代对象,即具有Symbol.iterator属性,返回一个迭代器对象。
解构并不要求右边是数组,只要右边是可迭代对象即可。
解构的本质
var [a, b] = arr;
// 第一步,调用arr[Symbol.iterator]()拿到迭代器iter
const iter = arr[Symbol.iterator]();
// 第二步,调用iter.next() 把得到的值赋值给a
var a = iter.next().value;
var b = iter.next().value;
解法一:在对象内部定义 Symbol.iterator 属性
我们可以在对象内部定义一个 Symbol.iterator 属性,该属性是一个函数,返回一个迭代器对象。
我们可以使用 Object.values 方法来获取对象的所有属性值,然后使用数组的 Symbol.iterator 方法来获取一个迭代器对象。
例如:
var [a, b] = {
a: 1,
b: 2,
Symbol.iterator {
var arr = Object.values(this);
const iter = arrSymbol.iterator;
return iter;
}
}
console.log(a, b); // 1 2
解法二:在Object.prototype上定义 Symbol.iterator 属性
我们也可以在 Object.prototype 上定义一个 Symbol.iterator 属性,这样所有的对象都会继承这个属性,从而变成可迭代对象。
这种方法的优点是不需要改变对象的写法,但是缺点是会影响所有的对象,可能会造成意想不到的结果。
例如:
Object.prototype [Symbol.iterator] = function() {
return Object.values(this)Symbol.iterator;
}
var [a, b] = {a: 1, b: 2};
console.log(a, b); // 1 2
解法三:使用生成器函数
我们还可以使用生成器函数来定义 Symbol.iterator 属性,这样可以更简洁地返回一个迭代器对象。
我们可以使用 yield* 关键字来委托给另一个可迭代对象,如 Object.values 方法返回的数组。
例如:
Object.prototype[Symbol.iterator] = function* () {
return yield* Object.values(this);
}
var [a, b] = { a: 1, b: 2 };
console.log(a, b); // 1 2
上例中,定义了一个生成器函数作为 Object.prototype[Symbol.iterator] 的属性。这个生成器函数使用 yield* 语法将 Object.values(this) 的迭代器的值逐个生成出来,并作为生成器函数的返回值。这样一来,当使用对象解构赋值时,会调用对象的 Symbol.iterator 方法,该方法返回的生成器函数会在每次迭代时生成 Object.values(this) 的值,并将其赋值给相应的变量。