JS基础总结之作用域

1、执行环境

执行环境(execution context)定义了变量或函数有权访问的其他数据。每个环境都有一个与之关联的变量对象,保存环境中定义的所有变量和函数。每个函数都有自己的执行环境。当执行流进入一个函数时,该函数的执行环境(变量对象)会被推入一个环境栈中,执行完毕之后弹出,保存的变量和函数定义被销毁,然后把控制权返回给之前的执行环境。

JS的执行环境主要分为以下三种情况:

  1. 全局环境——变量对象始终位于环境栈的最底部,代码运行时最先进入该环境。
  2. 函数环境(局部环境)——函数执行时进入该环境,当前执行函数的环境始终位于环境栈的最顶部。
  3. eval

当调用一个函数时,一个新的执行环境就会被创建。而一个执行环境的生命周期可以分为两个阶段:
 创建阶段
:在这个阶段中,执行环境会分别创建变量对象,建立作用域链,以及确定this的指向。
 代码执行阶段:阶段
创建完成之后,就会开始执行代码,这个时候,会完成变量赋值,函数引用,以及执行其他代码。

2、变量对象

新的执行环境创建时,会同步创建一个与之关联的变量对象。它存储着在环境中声明的以下内容:

  • 变量声明
  • 函数声明;
  • 函数的形参(arguments对象);

在函数执行时,进行变量对象的赋值,函数的引用等操作,对应的变量对象同时转换成为活动变量
变量对象和活动对象其实都是同一个对象,只是处于执行环境的不同生命周期。变量对象在转换成活动变量之前,属性不能被访问,转换之后可以访问。
举例说明:

function test(){
    var x=1;
    function inn(){
        var y=2;
        return y;
    }
}
alert(test());

其中的变量对象可以表示如下:

//变量对象创建时,
//函数text的变量对象
text_variableObject={
arguments:{},
x:undefined,
inn:<reference to function>//表示函数的引用
}
//函数执行时,变量对象转变为活动对象,进行变量的赋值和引用
text_activeObject = {
    arguments: {...},
    x: 1,
    inn: <reference to function>,    
}

3、作用域链

代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的前端始终是当前环境的变量对象,下一个变量对象来自外部一层环境,依次往后,直到全局执行环境的变量对象。解析过程一般都是从作用域的前端一级一级的往后回溯。作用域内层可以访问外层的变量。示例如下:

    var o="global";
    function outer () {
        var outerVar="outer";
        function inner(){
            var innerVar="inner";
            outerVar="outer-inner";
            o="global-inner";
            console.log(innerVar+","+outerVar+","+o);//inner,outer-inner,global-inner,可以访问外层变量
        }
        inner();
    }
    outer();

如下示例代码中,通常在C或者java语言,花括号封闭成自己的作用域,color变量在if执行完后会被销毁,而在JavaScript执行时,color并不会被销毁。也就是说,if语句没有形成自己的作用域,color变量定义时存在于整个执行环境中。

if(true){
    var color="blue";
}
alert(color);       //"blue"

使用var声明的变量会自动被添加到最接近的环境中。函数内部最接近的执行环境就是函数的局部环境。如果初始化变量时没有使用var声明,该变量会被自动添加到全局环境。

function test(){
    color="blue";
}
test();
alert(color);   //"blue"

示例中的color变量没有使用var声明,他被添加到了全局环境中,因此函数外部可以访问。

当局部环境与全局全局环境存在同名变量时,作用域链的搜索过程从前端开始,查询到该变量即会停止搜索。如下的示例,函数colorF执行时首先搜索到的color是局部环境中的变量,此时搜索停止,return执行使用这个变量。而要在局部环境访问全局的color,则只能使用window.color语句。

var color="blue";
function colorF(){
    var color ="red";
    return color;
}
alert(colorF());    //red

4、变量提升和函数提升

JavaScript还存在变量提升,即变量的声明总会被提升到方法体的最顶部。如下示例中,变量y在未声明时调用alert结果为“undefined”,说明y的声明已经被提升,而初始化没有被提升。(PS:严格模式下变量在没有声明的情况下使用会报错)

var x = 5; // 初始化 x
alert(x);  //5
alert(y);  //"undefined"
var y = 7; // 初始化 y

PS:ES6标准引入了变量声明let,用let声明的变量克服了这些问题。

JavaScript有两种函数创建方式:

  1. 函数声明
  2. 函数字面量方式

函数声明方式创建的函数存在函数声明提升的特征,即数声明语句会被提升到外部脚本或者外部函数作用域的顶部,因此可以先使用,后声明,示例如下:

f();
function f(){
console.log("f() is called!");
}

这段代码可以正常执行,说明函数声明已经被提升。

f();
var f=function(){
console.log("f() is called!");
}

这段代码执行时会报错,因为字面量方式定义的函数没有提升的特性。

5、扩充作用域

有些语句可以在作用域链的前端临时增加一个变量对象,使函数在某些指定的执行环境执行。

  1. try-catch语句的catch块
  2. with语句
  3. apply()和call()
  4. bind()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值