浅谈 JavaScript 作用域

一、什么是作用域

作用是对代码的一个读写操作,域是js能够实现的一个范围。

script标签中var的时候,其实是在最大的window上加了一个属性,如果在script中没有用var声明,而是直接赋值,那就是自动在window上加一个属性,这是系统在找不到声明的时候,自动加的。

console.log(a); //undefined
var a = 1;
console.log(a); //1
console.log(a); //报错
a = 1;
a = 1;
console.log(window.a);//1

二、解释器

  1. js是一种直译式脚本遇到,遇到script标签后,解释器就开始工作,没有一个长期的前期准备。
  2. 解释器执行js代码至少分两步:预解析和执行代码。
  3. 预解析阶段进行变量声明和函数声明,遇到var变量声明后,不去读取赋值,而是自动给变量赋值为undefined,遇到function函数声明后,不去读/执行函数,而是自动将函数的内容当成一块直接存起来function(){}。functionvar优先级高,遇到同名的变量名和函数名,函数名会将变量名进行覆盖,而变量名不会将函数名覆盖。如果有重名的函数,则后者会将前者覆盖。
  4. 解释代码/执行代码期间才真正改变变量的值,先找到预解析找到的变量和函数,如果有能改变变量值的运算=+*/%++--,则会修改预先的值。
alert(a); //function a(){alert(3)}
var a = 1;
alert(a); //1
    
function a(){
    alert(2);
} 
    
alert(a); //1
    
var a = 3;
    
alert(a); //3
    
function a(){
    alert(3);
}

alert(a) //3

a(); //报错

三、全局作用域和局部作用域

  1. 全局作用域:最大的作用域是script标签之间,全局中的最大对象是window,但是script标签是分别解释的,代码是自上而下执行的,script之后还是最大的window,在引入代码的时候,一定要注意引入顺序,因为script标签是分别解释的。
  2. 局部作用域:函数内部也是一个空间(函数构建的空间),可以被看做一个局部作用域。
  3. 如果局部作用域的“预解析空间”(AO-活动对象(Active object))没有找到,那么代码会从上一级的作用域寻找,上级作用域不能在下级作用域寻找。
<script type="text/javascript">
    alert(a); //报错
</script>
<script type="text/javascript">
    var a = 1;
</script>
<script type="text/javascript">
    var a = 1;
</script>
<script type="text/javascript">
    alert(a); //1
</script>
var a = 1;
function fn1(){
    alert(a); //undefined
    var a = 1;
}
fn1();
alert(a); //1

//window  1.Ao分析  {a:undefined,fn1:function(){}}
//
//        2. 代码执行: a = 1
//        
//        
//                    fn1 执行 : 进入到函数内部/函数所生成的局部作用域
//                            1. AO分析 {a:undefined} 
//                            2.执行
//                                  //                              
//                                  
//                                          
//           alert(a)
//                 
//  

四、参数

  1. 形参:相当于隐式声明,在AO上为undefined。
  2. 实参:会在AO分析的时候,给形参一个初始值。
var a = 1;
function fn1(a){
    alert(a); //undefined
    a = 2;
}
fn1();
alert(a); //1
// window 1. AO {a:undefined,fn1:function(){}}
//        2. AO {a:1,fn1:funcion(){}}
//              fn1:
//                  1.AO {a:undefined}
//                  2.alert(a); 
//                    AO {a:2}
//              
//              
//              alert(a)
//                      
var a = 1;
function fn1(a){
    alert(a); //1
    a = 2;
}
fn1(a);
alert(a); //1
// window 1.{a:un,fn1:function}
//        2.{a:1,fn1:function}
//              fn1: 1.{a:1}
//                   2. alert(1)
//                      {a:2}
//          alert(a)

五、作用域的AO分析

  1. 先看有没有参数,实参会把形参初始化,如果只有形参,那么形参为undefined。
  2. 再看有没有变量声明。
  3. 最后看有没有函数声明,函数会把同名变量覆盖。
var age = 99;
function t(age){
    alert(age); 
}
t(5); //5
t(); //undefined
// win 1.AO{age:un,t:fun}
//     2. AO{age:99}
//         t(5): 1. AO{age:5}
//               2. alert(5)
//         t(): 1 AO{age:un}
//              2. alert(un)
function t2(greet){
    alert(greet); //function greet(){}
    function greet(){}
    greet = 'hello';
    alert(greet); //hello
}
t2(null);
// t2 1. AO{greet:function(){}}
//    2. alert(greet)
//       AO{greet:"hello"}
//       alert(greet)
function a(b){
    alert(b); //function b(){alert(b);}
    function b(){
        alert(b); //function b(){alert(b);}
    }
    b();
}
a(1);
// a 1. AO{b:fun}
//   2. alert(b)
//     b()  1. b AO{}
//          2. alert(b)
function a(b){
    alert(b); //1
    b = function(){
        alert(b); //function(){alert(b);}
    }
    b();
}
a(1);
// a 1. AO{b:1}
//   2. alert(b)
//      {b:fun}

六、作用域链

  1. 内层作用域在寻找变量的时候未找到,会沿着作用域上的AO向上寻找,直到全局。
  2. AO成链就是作用域链。
//JQ最外层代码
// console.log(window);
// undefined = 1
;(function(window ,undefined) {
    // AO{window:window,undefined:1}
    function(){
        function(){
            function(){
                window.document.getElementById()
            }
        }
    }
})(window);
//写window 是为了 性能  不写undefined 是为了防止被污染
//在低版本的IE和FF浏览器当中 undefined是可以被赋值的
发布了87 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_38188762/article/details/105022654
今日推荐