JS笔记《变量解构赋值》

94 阅读5分钟

数组

  • 从数组中提取值,按照位置对变量赋值。只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值为undefined
  • 只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值。
let [a, b, c] = [1, 2, 3];
a // 1
b // 2
c // 3

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
  • 如果等号右边的不是数组(是不可遍历的结构),那么将会报错。
// TypeError: xx is not iterable
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"

默认值

  • 内部使用严格相等===来判断一个位置是否有值。只有当一个数组成员===undefined,默认值才会生效。
let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a'];
y // b

let [x, y = 'b'] = ['a', undefined];
y // b

let [x = 1] = [null];
x // null
  • 如果默认值是一个表达式,那么这个表达式是惰性求值的。当只有用到的时候才会求值。
function f(){
 return 'b';
}
let [a = f()] = [1];
a // 1  因为 a能取到值,所以函数f不会运行

let [b = f()] = [];
b // 'b' 取不到值才会执行函数f
  • 默认值可以引用解构赋值的其他变量,前提是该变量已经声明。
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = y, y = 1] = [];     // 报错 因为 x用y做默认值,但是y还没有声明

对象

  • 与数组解构赋值不同,数组是按照位置的对等进行的,而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。如果解构不成功,变量的值为undefined
// 正常的对象解构赋值:
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
// 可以简写为:
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }


// 对象嵌套解构赋值
const node = {loc: { start: { line: 1, column: 5 }}};
const {loc, loc: {start}, loc: {start:{line}}} = node;
loc   // {start: {line: 1, column: 5}}
start // {line: 1, column: 5}
line  // 1
  • 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
foo // foo is not defined  前者用于匹配同名属性
baz // 'aaa'   后者才是被赋值的变量
  • 对象的解构赋值可以很方便的将现有对象的方法赋值到某个变量。
let { log, sin, cos } = Math;

const { log } = console;
log('hello!');  // 相当于console.log('hello!')

默认值

  • 默认值生效的条件是,对象的属性值严格等于undefined
let {x = 3} = {};
x  // 3

let {x, y = 5} = {x: 1};
x // 1
y // 5

let {x: y = 3} = {};
y // 3

let {x: y = 3} = {x: 5};
y // 5

let {msg: msg = 'sb'} = {};
msg  // 'sb'

字符串

  • 字符串也可以解构赋值,因为字符串会被转为类数组。
const [a, b, c, d, e, f = '!'] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
f // "!"

let {length: len} = 'hello';
len  // 5

数值和布尔

  • 只要等号右边的值不是对象或数组,就先将其转为对象。
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

// undefined和null无法转为对象
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError

函数参数

  • 函数的参数也可以使用解构赋值。
// 参数表面上看是一个数组,但是在传入参数的那一刻,数组参数就被解构成了变量x和变量y,
// 对于函数内部来讲,就是参数x和y
function add([x, y]){
  return x + y;
}
add([1, 2]); // 3

// 例子一:
// 参数默认值是一个空对象,属性x默认值为0,属性y默认值为0
function move({x = 0, y = 0} = {}) {
  return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]   参数传了,但是 y属性没有,所以 y使用默认值
move({}); // [0, 0]  参数传了,但是没有x 和 y属性,所以都采用属性默认值
move(); // [0, 0]  未传参数,使用参数默认值{}。x 和 y 都采用默认值

// 例子二:
// 参数默认值为{ x: 0, y: 0 }。解构的属性没有默认值
function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]   // 参数传了,但是y属性没传,y也没有默认值,所以是undefined
move({}); // [undefined, undefined]  // 参数传了,但是x y都没有默认值,所以是undefined
move(); // [0, 0]   未传参数,使用参数默认值{ x: 0, y: 0 },解构x y都是0

用途

交换变量的值

let x = 1;
let y = 2;
[x, y] = [y, x];
x // 2
y // 1

从函数返回多个值

  • 函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象中返回。可以用解构赋值,一次取出多个值。
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

提取JSON数据

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

函数参数的默认值

  • 避免了函数体内部再写var foo = config.foo || 'default foo';
function request(url, {method = 'GET', loading = true, callback = function(){}})

遍历Map结构

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

// 获取键名
for (let [key] of map){...}
// 获取键值
for (let [, value] of map){...}

加载模块的指定方法

const { getUserInfo,  login } = require("source-map");