Javascript之函数声明和变量提升

简介

当浏览器拿到一段JavaScript代码的时候并不会去直接执行它,浏览器引擎会在执行JavaScript代码之前对其进行预编译。

总的而言就是下列两个步骤:

  • javascript预编译:就是通过语法分析和预解析构造合法的语法分析树,读取变量和函数的声明,并确定其作用域即生效范围。
  • javascript执行:执行具体的代码,JavaScript引擎在执行每个函数实例时,都会创建一个执行环境和活动对象(它们属于宿主对象,与函数实例的生命周期保持一致)

预编译阶段的一部分工作就是找到所有的变量和函数声明,并用合适的作用域与之关联起来。
因此,包括变量和函数在内的所有声明都会在其他代码执行前首先被处理

函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖

  • GO:全局上下文 全局预编译
  • AO:函数上下文 函数预编译

函数声明

  • 解析器在向执行环境中夹在数据时,对函数声明和函数表达式并非一视同仁。
  • 解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)。
  • 说白了就是,用函数声明形式定义的函数支持变量提升 ,而函数表达式形式的不行。
// 函数声明形式定义函数 foo(); function foo() { console.log("成功"); } // 结果:成功 // 上面代码相当于 function foo() { console.log("成功"); } foo();
// 函数表达式 foo(); var foo = function foo() { console.log("成功"); } // 结果:TypeError:foo is not a function
// 即使是具名的函数表达式,名称标识符在赋值之前也无法再所在作用域中使用 fn(); // TypeError vm(); // ReferenceError var fn = function vm() { console.log('1') };

变量提升

var定义的变量有变量提升
letconst定义的变量和常量不会变量提升

console.log(a) // undefined var a = 1

关卡

console.log(a) // [Function: a] function a(a) { var a = 10; var a = function () { } } var a = 1; /** * 相当于 * 函数提升(优先于变量提升):function a(a) {} * 变量提升:var a * console.log(a) * a = 1 */
function test() { var a = b = 1; // 这里相当于 var a = 1 b = 1 b前面没有var,是定义在全局的 } test(); console.log(b) // 1
if (!("a" in window)) { var a = 1; } console.log(a); // undefined /** * 上面代码相当于 * var a * if (!("a" in window)) { // 已经定义了a = undefined,所以不走这个if语句 * a = 1; * } * console.log(a); */
function test(a,b) { console.log(a); // 1 c = 0; var c; a = 5; b = 6; console.log(b); // 6 function b(){} function d(){} console.log(b) // 6 } test(1) /* * AO = { * a: undefined -> 1 -> 5 * b: undefined -> function b(){} -> 6 * c: undefined -> 0 * d: function d(){} * } */
var b = 3; console.log(a); // function a(){} function a(a) { console.log(a); // function a(){} var a = 2; console.log(a); // 2 function a() {} var b = 5; console.log(b); // 5 } a(1); /* * GO = { * b: undefined -> 3 * a: undefined -> function a() {} * } * AO = { * a: undefined -> 1 -> function a(){} -> 2 * b: undefined -> 5 * } */
function test(){ console.log(b); if(a){ var b = 2; } c = 3; console.log(c); } var a; test(); a = 1; console.log(a); /* * GO = { * a: undefined -> 1 * test: fucntion(){...} * c: undefined -> 3 * } * AO = { * b: undefined * } */
a = 1; function test(e){ function e(){} arguments[0] = 2; console.log(e); if(a){ var b = 3; } var c; a = 4; var a; console.log(b); f = 5; console.log(c); console.log(a); } var a; test(1); console.log(a); console.log(f); /* * GO = { * a: undefined -> 1 * test: function(){...} * f: undefined -> 5 * } * AO = { * e: undefined -> 1 -> function e(){} -> 2 * b: undefined * a: undefined -> 4 * c: undefined * } */
a() var a = c = function() { console.log(2) } a() function a() { console.log(1) } a(); (function(b) { b(), c() var b = c = function a() { console.log(3) } b() })(a) c() // 1 2 2 2 2 3 3 // 将 var(变量提升) 和函数声明提到最上面 上面代码就相当于下面的 var a; function a() { console.log(1) } a(); // 1 a = c = function() { console.log(5) } a(); // 2 a后面又定义了,所以覆盖了 a(); // 2 (function(b) { var b, c b(); // 2 b是形参,就是传入的a c(); // 2 var b=c=xxx 这里c相当于没有加var 不会预编译,这里c直接查找到外部作用域的c b = c = function a() { console.log(3); } b(); // 3 })(a); // 走到这里 a已经被赋值表达式重新赋值 c(); // 3 由于没加var 的原因 c已经被立即执行函数内部的赋值表达式改变了值 这里是3

创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: