Javascript闭包简单理解

提到闭包,想必你们都早有耳闻,下面说下个人简单理解。
平时写代码、第三方框架和组件都或多或少用到了闭包。
因此,了解闭包是很是必要的。呵呵...

1、什么是闭包
简而言之,就是可以读取其余函数内部变量的函数
因为JS变量做用域的特性,外部不能访问内部变量,内部能够外部变量。

2、使用场景
1. 实现私有成员。
2. 保护命名空间,避免污染全局变量。
3. 缓存变量。
缓存

先看一个封装的例子:
闭包

var person = function () {
    // 变量做用域为函数内部,外部没法访问
    var name = "default";

    return {
        getName: function () {
            return name;
        },
        setName: function (newName) {
            name = newName;
        }
    }
}();

console.log(person.name); // 直接访问,结果为:undefined
console.log(person.getName()); // 结果为:default
console.log(person.setName("langjt"));
console.log(person.getName()); // 结果为:langjt

再看循环中经常使用闭包解决引用外部变量问题:
框架

var aLi = document.getElementsByTagName('li');
for (var i=0, len=aLi.length; i<len; i++) {
   aLi[i].onclick = function() {
     alert(i); // 不管点击哪一个<li>元素,弹出的值都为len,代表这里的i和在for以后打印i的值是同样的。
   };
}

使用闭包后:
函数

var aLi = document.getElementsByTagName('li');
for (var i=0, len=aLi.length; i<len; i++) {
  aLi[i].onclick = (function(i) {
    return function() {
      alert(i); // 此时点击<li>元素,就会弹出对应的下标了。
    }
  })(i);
}

 

3、注意事项
1. 内存泄漏
因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题。
好比:
性能

function foo() {
   var oDiv = document.getElementById(‘J_DIV’);
   var id = oDiv.id;
   oDiv.onclick = function() {
     // alert(oDiv.id); 这里存在循环引用,IE低版本页面关闭后oDiv仍在内存中。因此尽量缓存基本类型而不是对象。
     alert(id);
   };
   oDiv = null;
}

 

2. 变量命名
若是内部函数的变量和外部函数的变量名相同时,那么内部函数再也没法指向外部函数那个同名的变量。
好比:spa

function foo(num) {
  return function(num) {
    console.log(num); 
  }
}
var f = new foo(9);
f(); // undefined

其实上面的用法,专业术语叫函数柯里化(Currying),就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数并且返回结果的新函数的技术。本质上也利用了闭包能够缓存的特性,好比:code

var adder = function(num) {
    return function(y) {
        return num+y;
    };
};

var inc = adder(1);
var dec = adder(-1);
//inc, dec如今是两个新的函数,做用是将传入的参数值 (+/‐)1
alert(inc(99));//100
alert(dec(101));//100 
alert(adder(100)(2));//102 
alert(adder(2)(100));//102

再好比阿里玉伯的seaJS源码中:对象

/**
 * util-lang.js - The minimal language enhancement
 */
function isType(type) {
  return function(obj) {
    return {}.toString.call(obj) == "[object " + type + "]"
  }
}

var isObject = isType("Object");
var isString = isType("String");
相关文章
相关标签/搜索