面试题

console.log(a)
var a = 10
function a() {}
console.log(a)
!function () {
    console.log(a)
    a = 5
    console.log(a)
    var a = 20
    console.log(window.a) 
}
();
console.log(a)

前置知识

变量提升 (Hoisting)

介绍变量提升之前,我们先通过下面这段代码,来看看什么是 JavaScript 中的声明赋值

var name = 'givencui'  // 初始化

等价写法

var name           // 声明部分
name = 'givencui'  // 赋值部分

再来看看, 函数的声明赋值 参考: MDN - 函数表达式


function foo(){
  console.log('foo')
}

var bar = function(){
  console.log('bar')
}

如图11

好了,理解了声明和赋值操作,那接下来我们就可以聊聊什么是变量提升了。

所谓的变量提升,是指在 JavaScript 代码执行过程中,JavaScript 引擎把变量的声明部分函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值,这个默认值就是我们熟悉的 undefined。

JS 代码的执行流程

JavaScript 代码的执行流程从概念的字面意义上来看,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,正如我们所模拟的那样。但,这并不准确。实际上变量和函数声明在代码里的位置是不会改变的,而且是在编译阶段被 JavaScript 引擎放入内存中。对,你没听错,一段 JavaScript 代码在执行之前需要被 JavaScript 引擎编译,编译完成之后,才会进入执行阶段。大致流程你可以参考下图:

img

基础问题

console.log(a) // undefined
var a = 10
console.log(a) // fn a
function a() {}

进阶问题

case1: 变量和函数同名的提升

可以在 chrome devTools 中验证

console.log(a) // fn a
var a = 10
function a() {}
console.log(a) // fn a
function a() {}
var a = 10

结论

  1. var 声明的变量 和 函数声明 都存在变量提升
  2. 同名变量和函数发生声明提升时, 函数声明优先级更高

解答开头的题目:

image-20210310190934787

case2: 函数为 IIFE

var a = 1;
(function a() {
  a = 2
  console.log(a)
})()
console.log(a)

运行结果如下:

image-20210310192801456

验证

var a = 1;
(function a() {
  console.log(Object.getOwnPropertyDescriptor(a, 'name'))
  a = 2  // 赋值失败
  console.log(a)
})()
console.log(a)

image-20210310195330724

严格模式下会报错

var a = 1;
(function a() {
  "use strict";
  a = 2
  console.log(a)
})()
console.log(a)

image-20210310195558490

结论:

  1. IIFE 本质是匿名函数表达式立即调用, 不是函数声明
  2. 函数表达式的函数名是只读的, 非严格模式下会赋值失败, 严格模式下会报错

本文由 givencui 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论