js 函数的执行环境和作用域链的深入解析

全局对象
       JS解释器开始运行时,在执行任何JS代码前,会创建一个全局对象,这个对象 的属性就是JS全局变量,并初始化为undefined。
       var声明一个JS全局变量时,实际上就是定义了一个全局对象的属性。
       非函数内部可以用this来引用这个全局对象
       客户端的JS中,Window对象代表浏览器窗口,它包含该窗口中的所有JS代码的全局对象,具有自我引用的window属性
局部变量:调用对象
       函数的局部变量存放在调用对象的属性
       调用对象是一个完全独立的对象,所以可以防止覆盖同名的全局变量
JS的执行环境
       JS解释器执行一个函数时,会创建一个执行环境
       JS允许同时存在多个全局执行环境,如:JS客户端的ifame的情况
深入理解变量作用域
       每个JS执行环境都有一个和它相关联的作用域链,它是一个对象列表或对象链.

       查询x:变量名解析(variable name resolution)的过程,它开始查看作用域链的每一个对象,如果有,返回值,如果没有继续查询下一个对象,以此类推.

       作用域链的优先级:嵌套函数的调用对象>调用对象>全局对象

       根据以上理解说明JS初始化的过程:
  •     在JS解释器执行任何代码之前,创建全局对象
                           用预定义的值和函数来初始化全局对象中的属性,eg.Math,Infinity,parseInt    
                           搜索函数外的var声明,创建全局对象相应的属性,初始化为undefined
                           创建全局的执行环境,作用域链只有一个对象-全局对象
  •     依次执行代码
                           遇到var声明赋值语句给全局对象相应的属性赋值
                           遇到未声明赋值语句,在全局对象中增加相应的属性,并赋值
  •     遇到函数调用,创建调用对象
                           搜索函数中的var声明和参数,创建调用对象相应的属性,初始化为undefined
                           创建函数执行环境,作用域链--第一对象:调用对象;第二对象:全局对象
                           依次执行代码
                                   遇到var声明赋值语句给调用对象相应的属性赋值
                                   遇到未声明赋值语句,在全局对象中增加相应的属性,并赋值
                                   遇到函数调用,创建嵌套函数的调用对象
                                  搜索嵌套函数中的var声明和参数,创建嵌套函数的调用对象相应的属性,初始化为undefined
                                   创建嵌套函数执行环境,作用域链--第一对象:嵌套函数的调用对象;第二对象:调用对象;第三对象:全局对象
     依此类推
eg1.
           var scope="global";
           function f(){
               alert(scope);
               var scope="local";
               alert(scope);
           }
           f();
           过程:
           创建全局对象,搜索函数外的var声明语句,在全局对象中创建scope属性,scope=undefined
           创建全局的执行环境,作用域链只有一个对象:全局对象
           依次执行代码:
               var scope="global"时,变量名解析开始,在全局对象属性中查找scope属性
               把"global"赋给scope
               遇到函数调用:创建调用对象
                   搜索函数中的var声明语句和参数,在调用对象中创建scope的属性,scope=undefined
                   创建函数执行环境,作用域链:调用对象>全局对象
                   依次执行代码:
                       alert(scope),查询scope,变量名解析,先搜索调用对象,找到scope属性,其值为undefined,执行
                       var scope="local",查询scope,变量名解析,先搜索调用对象,找到scope属性,scope="local"
                       alert(scope),查询scope,变量名解析,先搜索调用对象,找到scope属性,其值为"local",执行
         
       eg2.
           var scope="global";
           function f(){
               alert(scope);
               scope="local";
               alert(scope);
           }
           f();
       过程:
           创建全局对象,搜索函数外的var声明语句,在全局对象中创建scope属性,scope=undefined
           创建全局的执行环境,作用域链只有一个对象:全局对象
           依次执行代码:
               var scope="global"时,变量名解析开始,在全局对象属性中查找scope属性
               把"global"赋给scope
               遇到函数调用:创建调用对象
                   搜索函数中的var声明语句和参数,没有找到var声明语句
                   创建函数执行环境,作用域链:调用对象>全局对象
                   依次执行代码:
                       alert(scope),查询scope,变量名解析,先搜索调用对象,没找到scope属性,再搜索全局对象,找到scope属性,其值为"global"执行
                       scope="local",查询scope,变量名解析,先搜索调用对象,没找到scope属性,,再搜索全局对象,找到scope属性,scope="local"
                       alert(scope),查询scope,变量名解析,先搜索调用对象,没找到scope属性,再搜索全局对象,找到scope属性,其值为"local",执行
       eg3.
           scope1="global";
           alert(scope1);
           function f(){
               alert(scope2);
               scope2="local";
           }
           f();
       过程:
           创建全局对象,没有找到var声明语句,没有自定义的全局对象属性
           创建全局的执行环境,作用域链只有一个对象:全局对象
           依次执行代码:
               scope1="global"时,变量名解析开始,作用域链是没有找到scope1属性,在全局对象属性中创建scope1属性,并赋值为"global"
               alert(scope1)时,变量名解析开始,作用域链是找到scope1属性,其值为"global",执行
               遇到函数调用:创建调用对象
                   搜索函数中的var声明语句和参数,没有找到var声明语句
                   创建函数执行环境,作用域链:调用对象>全局对象
                   依次执行代码:
                       alert(scope2),查询scope2,变量名解析,作用域链是没有找到scope2属性,报错scope2 is not defined

由此而来的建议

1. 尽量使用局部变量,这不仅仅是涉及到私有属性的问题,局部的变量从以上过程中可以看到,能够减少搜索的时间(注:在一般的情况下,不包括浏览器的优化行为)。

2. 避免使用with语句。因为它会修改执行上下文(Execution Context)的作用域链,在最前面添加一个对象(Variable Object)。同理,对于try-catch语句中的catch语句块也类似。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值