⭐️ 变量提升、暂时性死区

var x = 1;

{
  let x = x;
  console.log(x); 
}

// Cannot access 'x' before initialization
// let形成暂时性死区,变量x没法在声明x这一步之前访问到
var x = 1;

{
  let y = x;
  console.log(y);  // 1
}

// let y 导致y在let之前形成了暂时性死区,而x没有,能从外层
// 作用域访问到var的x的值
let x = 1;

function foo(y = x) {
  let x = 2;
  console.log(y);
}

foo(); // 1

// 1. 变量提升:y: undefined
// 2. 实参赋值: y = x,就去找x。但let上边是暂时性死区,拿不到x。
// 就去全局找x=1,所以y=1
// 3. 函数内部 x = 2,y = 1

⭐️ 函数默认值会在()内形成一个单独的作用域

let x = 1;

function foo(x = 3) {
  let x = 2;
  console.log(x);
}

foo();

// Identifier 'x' has already been declared

// 函数默认值可以等效为 let x = 3 ,由于此刻就声明了x,
// 所以函数内部再次声明,报错
function foo(x = x) {
	console.log(x);
}

foo(); 
// Cannot access 'x' before initialization

// 上面代码可以理解为

// function foo(x = x) { => let x = x;
// }

// let x = x; 不能在赋值的时候访问变量自己
// 从而导致报错Cannot access 'x' before initialization
function foo(x = x) {
	let x = 2;
  console.log(x);
}

foo();

// 重复声明了x,Identifier 'x' has already been declared

⭐️ 重要案例

var w = 1, z = 2;

function foo(x = w + 1, y = x + 1, z = z + 1) {
  console.log(x, y, z);
}

foo();

// 1. let x = w + 1, x = 2
// 2. let y = 内部 x + 1, y = 3
// 3. let z = z + 1, 暂时性死区,初始化之前z不能被访问
var a = 1;

function test(a = a) {
  console.log(a);
}
test(); // ReferenceError: Cannot access 'a' before initialization