1、js的解析过程分为两个阶段:预编译期(预处理)与执行期。
预编译期JS会对本代码块中的所有声明的变量和函数进行处理(类似与C语言的编译),但需要注意的是此时处理函数的只是声明式函数,而且变量也只是进行了声明但未进行初始化以及赋值(即只是分配了内存)。在预编译的过程中,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率。变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined。变量的申明是在预编译期,初始化是在执行阶段。
//打印出a2/a1.函数内部里,a2覆盖了原来的a1,后面打印的是a1,因为在函数的外部打印出了是全局变量
var a="a1";function test(){var a="a2";console.log(a);}test();console.log(a);
//打印出undefined/a1,函数的内部,var a=“a2”定义了一个变量,这里用到了变量提升知识点,将变量a先声明并且提升到函数内部的第一句,而不进行赋值。则打印出undefined,后面则打印出全局变量
var a="a1";function test(){console.log(a);var a="a2";}test();console.log(a);
//打印出a2/a2,这里没有用var 声明变量,则成为了全局变量,后来的变量值则覆盖掉了原来的赋值。
var a="a1";function test(){a="a2";console.log(a);}test();console.log(a);
//打印出a1/a2,开始打印的是全局变量a1,执行到a="a2"时候,这时候的a2则覆盖掉之前的变量值a1,所以后来打印的是a2
var a="a1";function test(){console.log(a);a="a2"}test();console.log(a);
声明式函数与赋值式函数的区别在于:在JS的预编译期,声明式函数将会先被提取出来,然后才按顺序执行js代码。而赋值式函数则只会提升名称
function test() {foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // 函数表达式被赋值给变量'foo'
console.log("this won't run!");}
function bar() { // 名为'bar'的函数声明
console.log("this will run!");}}
test();
//foo()不能打印出,报错
//bar()能打印出 原因:只有以函数声明的方式定义的函数才能将函数主体部分一起提升到最前面,以函数表达式声明的函数只会提升名称 var foo;
总结:1、变量提升 a、函数内部用var 声明并且赋值了的变量无论放在哪个位置,都会将变量的声明都提升到第一行(这里只是将变量的声明提到第一行,但是不赋值)。b、函数内部:只有函数声明的方式会连函数体一起提升,而函数表达式中只会提升名称,函数体只有在执行到赋值语句时才会被赋值。
2、作用域:在js中是函数级作用域(function-level scope)。