Undefined 
- 已声明但没有赋值
 
声明方式 
| 关键字 | 变量提升 | 块级作用域 | 重复声明 | 可以改 | 
|---|---|---|---|---|
var | 作用域的顶部 | 无 | 允许 | 可以 | 
function | 块的顶部 | 无 | 允许 | 可以 | 
let | 没有 | 有 | 不允许 | 可以 | 
const | 没有 | 有 | 不允许 | 不可以 | 
class | 没有 | 有 | 不允许 | 可以 | 
解构赋值 
绑定与赋值 
js
let name;
let age;
const arr = [];
const obj = {};
({ name: arr[0], age: obj.age } = { name: "孙悟空", age: 18 }); //[!code warning]这里必须要有括号!js
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1Details
- 使用 var、let、const 关键字时为绑定模式
 - 不使用 var、let、const 关键字时为赋值模式
 - 赋值模式可以为已存在的变量或是对象属性赋值
 
默认值 
js
// 从对象中解构
const { name = "", age = 0 } = { name: "孙悟空", age: 18 };js
// 从数组中解构
const [name = "", age = 0] = ["孙悟空", 18];TIP
- 如果对象中没有对应有 key 或者数组中没有对应的 index,则会将新变量赋值为 undefined
 - 上述情况可以为该变量设置一个默认值
 
剩余属性 
js
const { name, ...restObj } = { name: "", age: 18 };
const [name, ...restObj] = ["", 18];解构嵌套 
js
const {
  a: { name },
  b: [age],
} = { a: { name: "孙悟空" }, b: [18] };其它语法中的解构 
除变量的声明和赋值外,还可以在以下场景使用解构:
for...in和for...of循环中- 函数的参数
 catch绑定变量
解构数组 
解构比源更多的元素 
js
const foo = ["one", "two"];
const [red, yellow, green, blue] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // undefined
console.log(blue); //undefined忽略某些返回值 
js
function f() {
  return [1, 2, 3];
}
const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
const [c] = f();
console.log(c); // 1使用绑定模式作为剩余属性 
js
const [a, b, ...{ pop, push }] = [1, 2];
console.log(a, b); // 1 2
console.log(pop, push); // [Function pop] [Function push]
const [a, b, ...[c, d, ...[e, f]]] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c, d, e, f); // 1 2 3 4 5 6DANGER
这个语法中不能用来解构对象
在任何可迭代对象上使用数组解构 
js
const obj = {
  [Symbol.iterator]: function* () {
    yield 1;
    yield 2;
    yield 3;
  },
};
const [a] = obj;
console.log(a);
const { length } = [];
console.log(length);解构对象 
赋值到新的变量名并提供默认值 
js
const { a: aa = 10, b: bb = 5 } = { a: 3 };
console.log(aa); // 3
console.log(bb); // 5从作为函数参数传递的对象中提取属性 
js
const user = {
  id: 42,
  displayName: "jdoe",
  fullName: {
    firstName: "Jane",
    lastName: "Doe",
  },
};js
// 从参数中提取 //[!code focus]
function userId({ id }) {
  return id;
}
console.log(userId(user)); // 42js
// 提取并重命名 //[!code focus]
function userDisplayName({ displayName: dname }) {
  return dname;
}
console.log(userDisplayName(user)); // `jdoe`js
// 从嵌套中提取并重命名 //[!code focus]
function whois({ displayName, fullName: { firstName: name } }) {
  return `${displayName} is ${name}`;
}
console.log(whois(user)); // "jdoe is Jane"js
// 设置函数参数的默认值 //[!code focus]
function drawChart({
  size = "big",
  coords = { x: 0, y: 0 },
  radius = 25,
} = {}) {
  console.log(size, coords, radius);
  // do some chart drawing
}
drawChart({
  coords: { x: 18, y: 30 },
  radius: 30,
});解构原始类型 
对象解构几乎等同于属性访问。这意味着,如果尝试解构基本类型的值,该值将被包装到相应的包装器对象中,并且在包装器对象上访问该属性。
js
const { a, toFixed } = 1;
console.log(a, toFixed); // undefined ƒ toFixed() { [native code] }DANGER
undefined 和 null 不能被解构
解构对象时查找原型链 
当解构一个对象时,如果属性本身没有被访问,它将沿着原型链继续查找。
js
const obj = {
  self: "123",
  __proto__: {
    prot: "456",
  },
};
const { self, prot } = obj;
// self "123"
// prot "456" (Access to the prototype chain)