混乱的 varfunction

造成混乱原因有:

var 声明的变量

// 'use strict'
// 严格模式无影响

console.log(globalThis.a)
console.log(a)
{
  console.log(globalThis.a)
  console.log(a)

  var a = 1

  console.log(globalThis.a)
  console.log(a)
}
console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

var a // !!! var 变量声明提升

console.log(globalThis.a) // undefined
console.log(a) // undefined
{ // !!! 无视块级作用域
  console.log(globalThis.a) // undefined
  console.log(a) // undefined

  a = 1 // !!! 赋值不提升
  globalThis.a = a // !!! 浏览器在全局作用域下会挂载到 globalThis;Node.js 不会

  console.log(globalThis.a) // 浏览器: 1; Node.js: undefined
  console.log(a) // 1
}
console.log(globalThis.a) // 浏览器: 1; Node.js: undefined
console.log(a) // 1
// 'use strict'
// 严格模式无影响

;(function () {
  console.log(globalThis.a)
  console.log(a)
  {
    console.log(globalThis.a)
    console.log(a)

    var a = 1

    console.log(globalThis.a)
    console.log(a)
  }
  console.log(globalThis.a)
  console.log(a)
})()

console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

;(function () {
  var a // !!! var 变量声明提升

  console.log(globalThis.a) // undefined
  console.log(a) // undefined

  { // !!! 无视块级作用域
    console.log(globalThis.a) // undefined
    console.log(a) // undefined

    a = 1 // !!! 赋值不提升
    // !!! 浏览器和 Node.js 在函数作用域下都不会挂载到 globalThis

    console.log(globalThis.a) // undefined
    console.log(a) // 1
  }
  console.log(globalThis.a) // undefined
  console.log(a) // 1
})()

console.log(globalThis.a) // undefined
console.log(a) // ReferenceError: a is not defined

函数声明

// 'use strict'

console.log(globalThis.a)
console.log(a)
{
  console.log(globalThis.a)
  console.log(a)

  function a() {}

  // do something

  function a() { 1 }

  console.log(globalThis.a)
  console.log(a)
}
console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

var a // !!! 非严格模式:函数声明提升到全局作用域或函数作用域

console.log(globalThis.a) // undefined
console.log(a) // undefined

{
  块内a = function a() {} // !!! 非严格模式:函数赋值提升到最近的块级作用域
  块内a = function a() { 1 } // !!! 重复声明

  console.log(globalThis.a) // undefined
  console.log(a) // [Function: a{1}]

  全局a = 块内a
  globalThis.a = a // !!! 非严格模式:浏览器在全局作用域下挂载到 globalThis; Node.js 不会

  // do something

  全局a = 块内a
  globalThis.a = a // !!! 遇到 function 或 var 就会判断是否需要挂载:是否全局作用域、是否严格模式、浏览器环境

  console.log(globalThis.a) // 浏览器: [Function: a{1}], Node.js: undefined
  console.log(a) // [Function: a{1}]
}
console.log(globalThis.a) // 浏览器: [Function: a{1}], Node.js: undefined
console.log(a) // [Function: a{1}]
'use strict'

console.log(globalThis.a)
console.log(a)
{
  console.log(globalThis.a)
  console.log(a)

  function a() {}

  console.log(globalThis.a)
  console.log(a)
}
console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

'use strict'

console.log(globalThis.a) // undefined
console.log(a) // ReferenceError: a is not defined
{
  function a() {} // !!! 严格模式:函数声明和赋值都提升到最近的块级作用域

  console.log(globalThis.a) // undefined
  console.log(a) // [Function: a]

  // !!! 严格模式:浏览器和 Node.js 在全局作用域下都不挂载到 globalThis

  console.log(globalThis.a) // undefined
  console.log(a) // [Function: a]
}
console.log(globalThis.a) // undefined
// !!! 严格模式:函数有块级作用域
console.log(a) // ReferenceError: a is not defined

未声明而直接赋值的变量

'use strict'

// !!! 严格模式不修正,访问未声明变量直接报错
a = 1 // ReferenceError: a is not defined
// 'use strict'

console.log(globalThis.a) // undefined
console.log(a) // ReferenceError: a is not defined
{
  console.log(globalThis.a) // undefined
  console.log(a) // ReferenceError: a is not defined

  a = 1 // !!! 修正为 globalThis.a = 1

  console.log(globalThis.a) // 1
  // !!! 相当于省略了 globalThis.
  console.log(a) // 1
}
console.log(globalThis.a) // 1
// !!! 相当于省略了 globalThis.
console.log(a) // 1

题目

// 'use strict'

console.log(globalThis.a)
console.log(a)
{
  console.log(globalThis.a)
  console.log(a)

  a = 1

  console.log(globalThis.a)
  console.log(a)

  function a() {}

  console.log(globalThis.a)
  console.log(a)
}
console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

var a // !!! 函数声明提升

console.log(globalThis.a) // undefined
console.log(a) // undefined
{
  块内a = function a() {} // !!! 函数赋值提升

  console.log(globalThis.a) // undefined
  console.log(a) // [Function: a]

  块内a = 1 // !!! 这里的 a 已经声明过了,而不是未声明而直接赋值

  console.log(globalThis.a) // undefined
  console.log(a) // 1

  全局a = 块内a
  globalThis.a = a // !!! 判断是否需要挂载

  console.log(globalThis.a) // 浏览器: 1, Node.js: undefined
  console.log(a) // 1
}
console.log(globalThis.a) // 浏览器: 1, Node.js: undefined
console.log(a) // 1
// 'use strict'

console.log(globalThis.a)
console.log(a)
{
  console.log(globalThis.a)
  console.log(a)

  function a() {}

  console.log(globalThis.a)
  console.log(a)

  a = 1

  console.log(globalThis.a)
  console.log(a)
}
console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

var a // !!! 函数声明提升

console.log(globalThis.a) // undefined
console.log(a) // undefined
{
  块内a = function a() {} // !!! 函数赋值提升

  console.log(globalThis.a) // undefined
  console.log(a) // [Function: a]

  全局a = 块内a
  globalThis.a = a // !!! 判断是否需要挂载

  console.log(globalThis.a) // 浏览器: [Function: a], Node.js: undefined
  console.log(a) // [Function: a]

  块内a = 1 // !!! 这里的 a 已经声明过了,而不是未声明而直接赋值

  console.log(globalThis.a) // 浏览器: [Function: a], Node.js: undefined
  console.log(a) // 1
}
console.log(globalThis.a) // 浏览器: [Function: a], Node.js: undefined
console.log(a) // [Function: a]
// 'use strict'

console.log(globalThis.a)
console.log(a)
{
  console.log(globalThis.a)
  console.log(a)

  function a() {}

  console.log(globalThis.a)
  console.log(a)

  a = 1

  function a() { 1 }

  console.log(globalThis.a)
  console.log(a)

  console.log(globalThis.a)
  console.log(a)
}
console.log(globalThis.a)
console.log(a)

// ------------- 相当于 -------------

var a // !!! 函数声明提升

console.log(globalThis.a) // undefined
console.log(a) // undefined
{
  块内a = function a() {}
  块内a = function a() { 1 } // !!! 函数赋值提升

  console.log(globalThis.a) // undefined
  console.log(a) // [Function: a{1}]

  全局a = 块内a
  globalThis.a = a // !!! 判断是否需要挂载

  console.log(globalThis.a) // 浏览器: [Function: a{1}], Node.js: undefined
  console.log(a) // [Function: a{1}]

  块内a = 1 // !!! 这里的 a 已经声明过了,而不是未声明而直接赋值

  全局a = 块内a
  globalThis.a = a // !!! 判断是否需要挂载

  console.log(globalThis.a) // 浏览器: 1, Node.js: undefined
  console.log(a) // 1

  console.log(globalThis.a) // 浏览器: 1, Node.js: undefined
  console.log(a) // 1
}
console.log(globalThis.a) // 浏览器: 1, Node.js: undefined
console.log(a) // 1

正常的 letconstclass

暂时性死区

使用 letconstclass 关键字声明变量时,这些变量会被提升到它们所在的作用域的顶部,这就是变量提升 (Hoisting)

但是,与 var 不同,声明的变量在声明之前是不可访问的。如果试图在声明之前访问这些变量,JavaScript 会抛出一个错误。这个从块的开始到变量声明位置之间的区域,就被称为“暂时性死区”(Temporal Dead Zone,TDZ)

箭头函数

function 函数的区别:

  1. this 指向定义环境上下文
  2. 不能作为构造函数
  3. 无原型对象和原型链
  4. arguments
  5. 不能作为 [[009.异步处理与 Promise#阶段三:Generator 函数|GeneratorFunction]]

箭头函数是“纯”函数,function 是函数 + 构造器

启示