JavaScript作用域学习笔记

Javascript作用域原理
理解 JavaScript 作用域和作用域链
作用域
作用域就是对变量和函数可访问的范围,作用域控制着函数和变量的可见性和生命周期

  • 全局作用域

    在代码中,任何地方都能访问到的的对象具有全局作用域。以下三种情况具有全局作用域。
    最外层函数和在最外层定义的变量具有全局作用域。

    var name = "cindy";      //全局变量
    function func(){        //全局
        var anotherName = "sam";
        alert(anotherName);
    }

    所有未定义直接赋值的变量自动声明为拥有全局性。

    var name = "cindy"; //全局
    function func(){        //全局
        var anotherName = "sam";
        name1 = "jack";   //全局
        alert(name1);
    }

    所有windows对象都拥有全局作用域。

  • 局部作用域

    与全局作用域相反,局部作用域一般只在固定的代码段中可以访问到,常见的就是定义在函数内部的变量。

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain),作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
作用域链是由一个一个变量对象链接起来的一个链,整个作用域链构成了当前执行环境中变量和函数可访问的范围,即作用域。由于变量对象是按一定顺序链接在一起的,所以就达到了对所有可访问变量、函数有序访问的效果。那么它们是按怎样的顺序链接成作用域链的呢?这就要说到活动对象。

当函数运行时就会为其创建一个活动对象,其中包含形参和函数特殊的arguments对象。活动对象之后会做为函数执行环境的变量对象来使用。

作用域链的前端,始终都是当前执行的代码所在环境的变量对象。但如果这个环境是函数,则将其活动对象作为变量对象,放在其作用域链的前端。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象来自下一个包含环境……这样一直延续到全局执行环境。全局执行环境的变量对象始终是作用域链中的最后一个变量对象。

为什么执行环境是函数会有这样特殊的规定呢?
JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里
在JavaScript中,一切都是对象,对象具有通过代码访问属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性就是[scope],这个属性包含了函数被创建的作用域中对象的集合,这个集合也称作为作用域链(scope chain);

函数被定义时,会将定义时刻的scope chain 链接到这个函数对象的[scope]属性上。
函数被调用时,就会创建一个活动对象(activation object),活动对象最开始只包含一个变量,即arguments对象(这个对象在全局环境中不存在的),然后对于函数的每一个形参,都命名为该活动对象的命名属性,然后将这个活动对象做为此时的作用域链最前端,并将这个函数的[[scope]]属性加入到作用域链中.

var name1 = "ben";
function func(){
    console.log(name1);
    var name1 = "john";
    console.log(name1);
}
func();

结果是

 undefined
 john

有人可能觉得会是

ben
john

在函数func被创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量。
这里写图片描述
执行此func函数时
这里写图片描述
在这里将调用参数赋值给形参数,对于缺少的调用参数,赋值为undefined。所以name1为undefined.所以在真正执行时,按照作用域链的排列来查询.
在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。

在执行console.log(name1);标识符解析,从最开始的活动对象查询到的为表中的undefined,在执行console.log(name1);标识符解析,将mark赋值给name1;所以结果是mark.

注意到, 因为函数对象的[[scope]]属性是在定义一个函数的时候决定的, 而非调用的时候。
如这个例子:

var name = "mark";
function intro(){
    console.log(name);
}
function changeName(){
    var name = "martin";
    intro();
}
changeName();

结果是

mark

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值