闭包(Closure)

时间:2022-07-23
本文章向大家介绍闭包(Closure),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、作用域及执行环境

要搞懂闭包首先得搞懂什么是作用域,作用域分为全局作用域局部(函数)作用域,每个作用域都有与他关联的变量对象(定义的所有变量和函数),作用域简单理解就是变量执行时的环境。

二、作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链作用域链最前端是当前执行代码的所在的环境变量对象。之后是他的外部作用域,之后是外部的外部作用域,直到作用域链终点为全局执行环境。

示例如下代码:
var name = 'kayle'
function getName () {
  // var name = 'innerKayle'
  console.log(name) // kayle
}
getName()

函数getName当他被调用时会创建一个执行环境及相应的作用域链,然后arguments和其他命名参数的值来初始化函数的活动对象。可以在函数内部访问到变量name,是因为能够在作用域链中找到它。

三、闭包

闭包是一个定义在其他函数内部的函数,他由函数及创建该函数的词法环境组合而成,这个环境包含了这个闭包创建时所能访问的所有局部变量。闭包可以访问三种作用域中的变量:

  1. 自身函数内声明的变量
  2. 父函数作用域中的变量
  3. 全局中声明的变量
在 JavaScript 中所有函数都是闭包的,因为他们都可以访问外部作用域
缺点:

外部调用函数完毕后,作用域链中任然占用其内部函数对象,会使得内部父函数中的变量也都被保存在内存中,内存消耗很大(直到解除该函数的引用)。

闭包例子

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()()); //The Window

这里之所以输出了The Window是因为原型链中找到了全局中的变量name

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()()); //My Object

不要为了闭包而闭包

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}

修改后

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};