JavaScript作用域-声明提升(个人总结)

mac2024-05-21  32

声明提升(hoisting)分为变量声明提升和函数声明提升。声明从它们在代码中出现的位置被“移动”到最上面的过程,被称作声明提升。每个作用域都会有声明提升。

在介绍作用域的内部原理时有提过,引擎在解释JS代码前首先进行编译,编译过程中会找到所有的声明,并用合适的作用域将它们关联起来。

以var a = 1;说明,这行代码包含了两步操作:var a和a = 1。定义声明是在编译阶段进行的,赋值操作是在执行阶段进行的。

// 示例1 var a = 1; var a; console.log(a) // 1; // 示例2 console.log(a) // undefined var a = 1; //等价于 var a; console.log(a); a = 1;

上面两个示例的奇怪行为,如果从声明提升的角度去看就很好理解了。

示例1声明了两次变量a,它们都在编译阶段完成声明,JS允许声明同名变量,到了执行代码时,对a进行赋值操作,执行到第3不自然打印结果就是1。

示例2也是同理,声明完成后a的值默认是undefined,到了执行阶段,赋值操作是在打印操作前完成的,所以结果就是undefined。

注意: 每个作用域都会进行声明提升。

console.log(a); var a = 1; function foo() { console.log(b); var b = 2; function foo2() { console.log(c); var c = 3; } foo2(); } foo(); // undefined undefined undefined

声明提升后是下面这样

var a; console.log(a); a = 1; function foo() { var b; console.log(b); b = 2; function foo2() { var c; console.log(c); c = 3; } foo2(); } foo(); // undefined undefined undefined

函数声明提升

// 提升前 foo(); function foo(){ console.log(1);//1 } // 提升后 function foo(){ console.log(1);// 1 } foo();

函数的调用在函数声明前也可以正常执行,就是因为函数声明提升的原因。

函数声明可以提升,但是函数表达式不会提升。

foo(); var foo = function() { console.log(1); // foo is not a function } // 等价于 var foo; foo(); foo = function() { console.log(1); // foo is not a function }

函数覆盖

既然函数声明和变量声明都会提升,如果出现了同名的函数或变量,谁的优先级更高呢?以下是我个人总结的一套简单的记忆规则,仅供参考。

把函数的权重默认为1,只声明未赋值的变量权重为1,声明且赋值的变量权重为2。高权重覆盖低权重,同权重后者覆盖前者。

// 测试1 权重相等,后者覆盖前者 var a; function a() {}; console.log(a); function a(){}' // 测试2 变量权重大于函数,输出变量值 var a = 1; function a(){} console.log(a);//1 // 测试3 第一行权重大于第二行,输出1 var a = 1; var a; console.log(a);//1 // 测试4 权重相等,后者覆盖前者 a();//2 function a(){ console.log(1); } function a(){ console.log(2); }

养成良好的开发习惯,避免在同一作用域中定义同名的变量或函数。

最新回复(0)