javascript 之闭包、作用域链

执行环境与作用域

执行环境

执行环境都有一个关联的变量对象,环境中定义的变量和函数都是这个对象的属性和方法。

  1. 全局执行环境——window对象(web浏览器中)
  2. 局部(函数)执行环境

全局变量对象始终存在,而局部变量对象只在函数执行过程中存在。

作用域

分为全局和局部作用域
ES6有了块级作用域。

作用域链

当在一个环境中执行时,会创建变量对象的作用域链,作用域链保存在函数的内部属性 [[scope]] 中,保证对执行环境有权访问的变量和函数进行有序访问。

  1. 作用域链前端:当前执行环境的变量对象->包含环境的变量对象->下一层包含环境的变量对象......->全局环境变量对象

  2. 标识符解析时:从作用域链前端一级一级的搜索,向后回溯,没有找到就报错。

作用域链本质上是一个指针列表,指针指向变量对象。

Note:
函数环境中,活动对象为变量对象,初始仅包含arguments对象
延长作用域链: catch 和 with 语句

闭包

闭包就是可以访问另一个函数作用域中变量的【函数】。

function animals(name){
    return function(){
        console.log(name);
    };
}
var a = animals("cat");
a();    //cat

内部的匿名函数的作用域链包含了自己、外部函数变量对象和全局变量对象,即使外部函数运行结束,外部函数的作用域链销毁,其外部函数变量对象仍被匿名函数作用域链所引用,所以外部函数变量对象一直在内存里,在这个匿名函数销毁时,才会销毁它的作用域链所引用的变量对象。

闭包一些问题

  1. 闭包占用内存
  2. 闭包保存整个变量对象,使用闭包是引用到的都是同一个变量
  3. 闭包的 this 一般指向 window
  4. 内存泄漏:如果闭包中保存了HTML元素,那这个元素将无法被销毁

模仿块级作用域

function test(){
    for(var i=0; i< 10; i++){
        console.log(i);
    }
    console.log(i); //在这里还可以访问到 i
}

模仿块级作用域的语法示例:

function test(){
    (function(){
        /*块级作用域*/
        for(var i; ...){...}
    })();
    console.log(i); //报错~
}

常用在全局作用域添加函数,避免全局作用域的变量和函数过多。

私有变量

用在构造函数上,为自定义类型创建私有变量、私有函数和特权方法

//
function Person(name){  //name和age是私有变量
    var age = 10;
    function myAge(){  //私有函数
        return age;
    }
    this.getAge = function(){
        return myAge(); //用特权方法访问私有函数和属性
    }
    this.getName = function(){  //特权方法
        return name;
    };
    this.setName = function(newName){   
        name = newName;
    };
}

//静态私有变量

(function(){
    var name = "";
    Person = function(value){
        name = value;
    };
    Person.prototype.getName = function(){
        return name;
    };
    Person.prototype.setName = function(value){
        name = value;
    };
})();
var p1 = new Person("Sam");
console.log(p1.getName());      //Sam
var p2 = new Person("Ben");
console.log(p2.getName());      //Ben
console.log(p1.getName());      //Ben

模块模式

var add = (function(){
    var count = 0;
    return {    //返回一个对象,定义公共接口访问私有变量和函数
        increase: function(){  return count += 1; },
        decrease: function(){   return count -= 1; },
        value: function(){  return count; }
    };
})();
add.increase(); //
console.log(add.value());

猜你喜欢

转载自www.cnblogs.com/qiuqiubai/p/12549670.html