作用域、作用域链

268 阅读4分钟

作用域

简单来说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。

函数的作用域:函数内的区域,就是这个函数的作用域,变量和函数在这个区域都可以访问操作。最外层函数外的区域叫全局作用域,函数内的区域叫局部作用域。

注:在函数内部声明变量的时候,要使用var进行声明。如果不用的话,你实际上声明了一个全局变量!

变量的作用域:变量所在的区域,就是这个变量的作用域,变量在这个区域内可以被访问操作。在全局作用域上定义的变量叫全局变量,在函数内定义的变量叫局部变量。

[[scope]]:每个JavaScript函数都是一个对象,对象中的有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。

[[scope]]就是我们所说的作用域,其中存储了执行上下文的集合。

执行上下文:当函数执行时,会创建一个成为执行上下文的内部对象。一个执行上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。

作用域链:[[scope]]中存储的执行上下文对象的集合呈链式连接,我们把这种链式连接叫做作用域链。

通俗地讲,当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链。

1.当执行函数时,总是先从函数内部找寻局部变量
2.如果内部找不到(函数的局部作用域没有),则会向创建函数的作用域(声明函数的作用域)寻找,依次向上

例子:

    function a() {
        console.log(a) //undefined
        function b() {
            var b = 234;
            console.log(a);  //123
        }
        var a = 123;
        console.log(a); //123
        b();
    }
    var glob = 100;
    a();

a函数被定义时,发生如下过程

在这个a函数刚刚出生时,是它的定义环节,它的scope里面就存了一个GO(Global Object)。

a函数被执行时,发生如下过程

a执行的时候发生了一个改变,一个函数执行要产生一个执行上下文AO,并放在作用域链的顶端

此时在a函数里面访问一个变量,系统会去a的scope里面找这个变量,它里面放的是个链,系统会先去作用域链的顶端去找,然后一次向下去找。(查找变量:从作用域链的顶端依次向下查找)

b函数被创建时,发生如下过程

b函数在执行时,会生成自己的执行上下文,并放在作用域链的最顶端。

当函数执行完后,它会把自己产生的执行上下文销毁,回归到自己定义的状态,等待下次被执行。

提到作用域就不得不提到闭包,简单来讲,闭包外部函数能够读取内部函数的变量。

优点:闭包可以形成独立的空间,永久的保存局部变量。
缺点:保存中间值的状态缺点是容易造成内存泄漏,因为闭包中的局部变量永远不会被回收。

简单例子:

 function test(){
            var arr =[];
            for(var i = 0; i< 10; i++){
                arr[i] = function (){
                    document.write(i+" ");
                }
            }
            return arr;
        }
        var myArr = test();
        for( var j = 0; j<10; j++){
            myArr[j]();
        }

结果:

闭包的作用:

1.实现公有变量
2.可以做缓存(存储结构)
3.可以实现封装,属性私有化
4.模块化开发,防止污染全局变量

1.例子:不依赖于外部变量并且能执行的函数累加器

     function add() {
        var num = 0;
        function a() {
            console.log("执行次数:" + ++num)
        }
         return a;
    }
    var myAdd =add();
    myAdd();
    myAdd();
    myAdd();
    

2.缓存效果

     function test() {
            var food = "apple";
            var obj = {
                eatFood: function () {
                    if (food != "") {
                        console.log("I am eating" + food);
                        food = "";
                    } else {
                        console.log("There is nothing!");
                    }
                },
                pushFood: function (myFood) {
                    food = myFood;
                }
            }
            return obj;
        }
        var person = test();

        person.eatFood();
        person.eatFood();
        person.pushFood('banana');
        person.eatFood();