Js代码分为两个阶段:编译阶段和执行阶段javascript
Js代码的编译阶段会找到全部的声明,并用合适的做用域将它们关联起来,这是词法做用域的核心内容java
包括变量声明(var a)和函数声明(function a(){})在内的全部声明都会在代码被执行前的预编译阶段首先被处理浏览器
过程就好像变量声明和函数声明从他们代码中出现的位置被移动到执行环境的顶部,这个过程就叫作提高函数
只有声明操做会被提高,赋值和逻辑操做会被留在原地等待执行code
Js编译器会把变量声明当作两个部分分别是声明操做(var a)和赋值操做(a=2)ip
声明操做在预编译阶段进行,声明操做会被提高到执行环境的顶部,值是undefined(表示未初始化)作用域
赋值操做会被留在原地等待执行阶段编译器
1 var a = 2; 2 3 function foo() { 4 console.log(a); //undefined 5 var a = 10; 6 console.log(a); //10 7 } 8 9 foo(); 10 11 // 至关于 12 13 var a = 2; 14 15 function foo() { 16 var a; 17 console.log(a); //undefined 18 a = 10; 19 console.log(a); //10 20 } 21 22 foo();
定义函数有两种方式:函数声明和函数表达式io
函数声明提高会在预编译阶段把声明和函数体总体都提早到执行环境顶部,因此咱们能够在函数声明以前调用这个函数console
函数表达式,其实就是变量声明的一种,声明操做会被提高到执行环境顶部,并赋值undefined。赋值操做被留在原地等到执行。
1 // 函数声明 2 3 foo(); //100 4 5 function foo(){ 6 console.log(100); 7 }
1 // 函数表达式 2 baz(); // TypeError: baz is not a function 3 4 var baz = function(){ 5 console.log(200); 6 } 7 8 //至关于 9 10 var baz; 11 12 baz(); 13 14 baz = function() { 15 console.log(200); 16 };
Js中使用函数级做用域,不存在块级做用域。全部普通块中的声明都会被提高到顶部,因此控制语句对声明的控制就显得彻底没有效果
1 if (false) { 2 var a = 10; 3 } 4 5 console.log(a); //undefined 6 7 // 至关于 8 9 var a; 10 if (false) { 11 a = 10; 12 } 13 14 console.log(a) //undefined
1 console.log(a); //undefined 2 3 if (false) { 4 function a() { 5 console.log(100); 6 } 7 } 8 9 a(); //TypeError: a is not a function 理论上应该是100
奇怪吧??函数提高发生在全部代码执行以前,因此尽管a函数的定义过程写在了if分支中,可是理论上,它是不会影响函数声明提高的
在新版本的浏览器中会出现此问题,旧版本的浏览器中会在控制台中打印出100
这也提醒了咱们尽可能不要在控制语句中进行声明,会形成不少没法预知的bug
提高操做会优先进行函数的声明
函数会首先被提高而后才是变量,重复的变量声明会被忽略,只剩下赋值操做,多个函数声明能够进行覆盖
声明的顺序是这样的:
找到全部的函数声明,初始化函数体,若有同名的函数则会进行覆盖
查找变量声明,初始化为undefined,若是已经存在同名的变量,就什么也不作直接略过
1 // 1 2 foo(); //200 3 4 function foo() { 5 console.log(100); 6 } 7 8 function foo() { 9 console.log(200); 10 } 11 12 // 2 13 console.log(foo); //function foo(){...} 14 15 function foo(){ 16 console.log(200); 17 } 18 var foo = 100;