JavaScript作用域,预解析

139 阅读4分钟

作用域

作用域:变量在某个范围内起作用,这个起作用的范围就称为作用域。在es6之前js只有全局作用域和局部作用域。根据作用域变量可分为全局变量和局部变量。

全局作用域和全局变量

全局作用域:作用于整个script标签,或者一个js文件。

全局变量:在全局作用域下声明的变量(在函数外部定义的变量)。

注意:如果在函数内部没有声明就直接赋值的变量也属于全局变量。

//a为全局变量
var a = 1;
console.log(a);

//b没有声明,直接赋值,为全局变量
function fn(){
    b = 2;
}
//结果为2
console.log(b);

局部作用域和局部变量

局部作用域:作用于函数内部,变量名只在函数内部起作用。

局部变量:在局部作用域下定义的变量。

注意:函数的形参也可以看成局部变量。

//num1也可以看成局部变量
function fn(num1){
// a为局部变量
 var a = 1;
}
fn(2);

全局变量和局部变量两者的区别

  1. 作用域不同;
  2. 执行效率不同:全局变量只有浏览器关闭的时候才销毁,占内存资源。局部变量当程序执行完毕就会被销毁,节约内存。

块级作用域

js是在es6新增的块级作用域。先省略(到es6特性的时候一起写)。。。

作用域链

内部函数可以访问外部函数的变量,采取链式查找来决定取哪个值,这种结构称为作用域链(就近原则)。

//全局变量
var a = 1;
//外部函数
function fn1(){
    var a = 2;
    //内部函数
    function fn2(){
        //输出 2
        alert(a);
    }

}

预解析

JS引擎运行JS代码分为两步:预解析 代码执行

  1. 预解析:JS引擎会把JS里所有的var 和 function 提升到当前作用域的最前面。
  2. 代码执行:按照代码书写的顺序从上往下执行。

预解析分为变量预解析(变量提升)和函数预解析(函数提升)

  1. 变量提升:把所有的变量声明提升到当前作用域的最前面,但不进行赋值操作。
  2. 函数提升:把所有的函数声明提升到当前作用域的最前面,但不调用函数。

变量提升的例子:

//运行结果:undefined
alert(num);
var num = 1;

//相当于执行了以下的代码
//进行变量提升但不赋值
var num;
//其余代码顺序不变
alert(num);
num = 1;

命名函数提升的例子:

//运行结果:1
function fn(){
    alert(1);
}
fn();

//相当于执行了以下代码
//函数进行预解析
function fn(){
    alert(1);
}
fn();

匿名函数变量提升的例子:

//结果报错
fn();
var fn = function(){
    alert(1);
}

//相当于执行了以下代码
//因为匿名函数是以变量名进行定义和调用,所以先是进行变量解析(变量定义)
var fn;
//此时调用fn(),相当于在调用一个未赋值的变量,报错。
fn();
//再按顺序进行赋值
fn = function(){
    alert(1);
}

预解析案例

案例1:

//运行结果 undefined
var num = 1;
fun();
function fun(){
    alert(num);
    var num = 20;
}

//相当于执行了以下代码
//首先进行全局作用域的变量和函数解析
var num;
funvtion fun(){
    //在函数内部进行预解析
    var num;
    alert(num);
    num = 20;
}
num = 1;
fun();

案例2

// 结果 undefined 2
var num = 1;
function fn(){
    console.log(num);
    var num = 2;
    console.log(num);
}
fn();

//相当于以下代码
var num;
function fn(){
    var num;
    console.log(num);
    num = 2;
    console.log(num);
}
num = 1;
fn();

案例3

//运行结果 undefined 9
var a = 18;
fn();
function fn(){
    var b = 9;
    console.log(a);
    console.log(b);
    var a = '123';
}

案例4:注意集体声明的格式:var a = 1,b = 1,c = 1;如果是var a=b=c=1;则相当于var a = 1;b=1;c=1;b和c为直接赋值并未声明,为全局变量。

//运行结果 1 1 1 1 1 报错
fn();
console.log(c);
console.log(b);
console.log(a);
function fn(){
    //b和c为全局变量
    var a = b = c = 1;
    console.log(a);
    console.log(b);
    console.log(c);
}
//相当于运行以下代码
function fn(){
    var a;
    a = b = c = 1;
    console.log(a);
    console.log(b);
    console.log(c); 
}
fn();
//c,b都为全局变量,a未在全局中定义
console.log(c);
console.log(b);
console.log(a);