作用域 预解析 作用域链

31 阅读4分钟

作用域

表示变量可以发挥作用的域 能够对某个变量寻址(调用 赋值)正常访问的域

作用域变量寻址规则

1.javascript 有作用域概念
    script是 全局域
    函数是 局部域 ,if() for()这些控制流程语句 不构成作用域
    函数内的变量 是 局部变量
2.局部内可以访问全局变量,局部外不可以访问局部内的私有变量
3.私有变量 是指 在当前局部作用域下 声明的变量,如果没有声明变量符 就不是当前作用域的私有变量
4.在调用没有声明的变量的的时候,会向上一级作用域寻找声明 一直找到 全局作用域为止
5.变量的访问 优先访问自己作用域内的局部变量,自己作用域找不到,向上寻找调用
6.如果一个变量 在局部作用域中直接使用 但是没有声明 并且向上一直寻找到 全局作用域 也没有 var 声明,js引擎会在全局作用域进行隐式声明

`function fn(){
    var x = y = 10;
}
fn();
console.log(y);//返回10
console.log(x);//报错 外面不能调用内部的
`
var x = y = 0;
可以拆分为 
         var x;
         y = 10;
         x = y;
         x为局部作用域的私有变量
         y没有声明 向上层作用域寻找
         y是通过隐式声明的全局变量

JavaScript引擎会对代码进行预解析

规则如下:
    1.寻找所有的声明 并提升【提升到当前作用域的最前面】(形如这样的都是声明语句 1.变量声明var 2.函数声明function fn(){}; 先提升变量 再提升函数)
    2.按照顺序 执行所有的 执行语句
    3.一层一层的作用域进行解析  先解析全局作用域 然后解析局部作用域
`var x = 10;
function fn(){
    //var x;(这是声明的提升)
    console.log(x); //返回值为undefined
    var x = 20;
}
fn();`
    因为函数内部的声明提到的 当前作用域 的前面

作用域链

1.作用域嵌套 就是函数嵌套关系 可以向上级获取 不能向下级获取
2.当前作用域内变量调用 优先调用自身局部变量 如果自身局部作用域没有声明 向上一级查询
  1.  `var x = 10;
        function x(){
            x = 20;
        }
        x();
        console.log(x);`
        这个函数会报错,原因如下:
         1.声明提升
         var x;
         function x(){};
         2.顺序执行 执行语句
         x = 10;
         x();//10() 报错 不是一个函数
         console.log(x);
 
  2.先提升变量 再提升函数
        `console.log(x);//返回的结果是函数 f x() {}
        var x= 10;
        function x() {
            x = 20;
        }
        x();`
    
  3.js没有动态作用域,函数在声明的时候,里面调用的变量就确定了变量属于哪个作用域
        `var x = 20;
        function fn1(){
            console.log(x);//x为全局变量 打印值为40
        }
        x = 30;
        function fn2(){
            var x = 1;
            fn1();
        }
        x = 40;
        fn2();`
    
  4.有if语句 需要判断if语句是否运行 (0 '' NaN undefined null都是false)
        `var x = 20;
        function fn(){
            if(x){ //var x = 30;声明提升var x再if前面,x为undefined
                var x = 30;//不一定执行
            }
            console.log(x);//返回值为undefined
        }
        fn();
        console.log(x);//返回值为20`
    
  5.声明提升中,提升再最前面的内容,执行语句 放在最前面的执行语句
        `function fun(param){
            console.log(param);
            var param = function (){
                console.log(1);
            }
            console.log(param);
        }
        fun(5);`
        以下是该函数的声明提升
        var param;//声明提升中,提升再最前面的内容
        param = 5;//执行语句 放在最前面的执行语句,因为后面要使用这个形参
        console.log(param);//返回值是5
        param = function(){
            console.log(1);
        }
        console.log(param);//返回值是f(){console.log(1);}
  6.foo的函数声明和变量声明都是(开辟一个名称为foo的地址空间)主要看赋值是什么,就返回什么
        `var foo = 1;
        function bar(){
            function foo(){}
            foo = 10;
            console.log(foo);//
        }
        bar();
        console.log(foo);`
        以下是声明提升解析
         var foo;
         function bar(){}
         
         foo = 1;
         bar();
             function foo(){}//声明了一个标识符名称为foo的内存地址 默认存储内容为函数体,和var foo;一样区别在于,前者的默认值是函数,后者默认值是undefined
             foo = 10;
             console.log(foo);//局部foo 返回值为10
        console.log(foo);//返回值为1