再来看看js函数的变量提升

49 阅读5分钟

我们先简单的看几组示例 , 之后简单的回答一下结果及其原因 , 之后展开探讨一下😁

几组示例

console.log(name)
var name="wql"

打印的结果 : undefine

答 : 变量提升 , 所以就是undefine. (后面详细解释)

console.log(a)
let a;

答 : 打印 : Cannot accesss 'a' before initialization ,这是由于“ 暂时性死区”造成的。

关于let const var三者在作用域和变量提升的区别 , 可以参考我之前的一篇文章

const ? let ? var ? ,包你神清气爽 !😎

console.log(fun)

function fun(){

}

打印结果 : [Function: fun]

答 : 函数也会提升 , 不只提升声明 , 值也会提升

那么为什么会变量提升 ?

  • 编译阶段的处理 JavaScript 代码在执行前会经历编译阶段(短暂的编译)。在编译过程中,JavaScript 引擎会对代码进行词法分析、语法分析等操作。当它遇到变量声明(使用 var关键字,对于 letconst有部分不同情况)和函数声明时,会先将这些声明提取出来,放到作用域的顶部。这样做的目的是为了在执行代码时,能够预先知道这些变量和函数的存在,方便后续对它们的引用和操作。
  • 作用域规则的需要 JavaScript 有自己的作用域规则,变量和函数的作用域在代码执行前就需要被确定。通过变量提升,能够确保变量在它所属的作用域内是可以被访问的,即使在声明之前就进行了引用。例如,在一个函数内部,如果没有变量提升,那么在变量声明之前就使用这个变量可能会导致错误,因为 JavaScript 引擎可能无法识别这个变量。而变量提升使得 JavaScript 能够按照自己的作用域规则来处理变量和函数,保证代码在一定程度上的灵活性和可维护性。

函数的声明和值为什么都提升了 ?

1)编译阶段

  • 在 JavaScript 代码执行前的编译阶段,引擎同样会对函数声明进行扫描和处理。与变量声明(使用 var关键字)类似,函数声明也会被提前提取出来,但函数声明的处理方式更为特殊。
  • 当引擎遇到函数声明时,它不仅仅是将函数的名字提升到作用域的顶部,而是会完整地将整个函数的定义(包括函数体等内容)一起提升。这意味着函数在这个时候就已经被完整地创建好了,包括其内部的逻辑和可执行代码。

2)函数作为可执行代码单元的特性

  • 函数是一段可执行的代码单元,它有自己的逻辑和行为。在 JavaScript 的设计理念中,希望函数在其作用域内能够随时被调用,即使在函数声明之前就进行调用尝试。

例如,在一个较大的代码文件中,如果函数的声明没有和它的可调用性紧密结合(即只提升声明而不提升值,意味着在声明之前调用函数时函数还不存在完整的可执行体),那么代码的逻辑连贯性和可维护性将会受到很大影响。因为开发者可能需要时刻注意函数声明的具体位置 ,确保在调用函数之前函数已经被完整地定义好了,这增加了不必要的复杂性。

我们看看下面这个例子 :

// 先尝试调用函数foo,此时函数声明还未出现
foo(); 

function foo() {
    console.log("函数foo被调用了");
}

// 再尝试调用函数bar,这里会报错,因为只提升了变量声明,函数值未提升
bar(); 

var bar = function() {
    console.log("函数bar被调用了");
};

首先,我们尝试调用函数 foo

在 JavaScript 中,由于函数声明会被整体提升(声明和值同时提升),所以即使在代码文件开头就调用 foo,在执行到这一行时,JavaScript 引擎已经在编译阶段将函数 foo的完整定义(包括函数体)提升到了当前作用域的顶部。因此,这次调用能够成功执行,控制台会输出 函数foo被调用了

然而,对于函数 bar的情况就不同了。这里我们使用了函数表达式的形式来定义函数(通过 var bar = function() {...}),这种情况下,使用 var关键字声明的变量 bar会被提升,但此时它的值只是 undefined,因为函数表达式赋值是在执行阶段才会进行的。

所以当我们在声明之前就尝试调用 bar时,就会报错,提示类似 TypeError: bar is not a function(不同浏览器可能报错信息略有差异)的错误。

这就体现了如果函数只提升声明而不提升值,在实际代码编写中会带来问题, 我们需要格外小心函数声明和调用的顺序,否则就会出现错误,进而影响代码的逻辑连贯性和可维护性。

通过这样的对比,可以清楚地看到函数声明和值同时提升在保证代码能够顺利运行以及提高代码可维护性方面的重要性。😀