JS闭包的概念。。。这两个函数让我凌乱了,他们同样可以返回局部变量,但是我还是分不清区别在哪

码疯
  • 165
function f1(){
    var a=1;
    return a;
}
function f1(){
    var b=1;
    function f2(){
        return b;
    }
    return f2;
}

按照闭包的概念:“函数体内的变量可以保存在函数作用域内的特性就叫做闭包”,第二个才是闭包,但是他们所实现的结果是一样的,他们同样可以实现在函数外面访问函数内部变量的效果,那么第一个f1()函数和第二个具体的区别在哪里呢?

回复
阅读 3.8k
9 个回答

我脚着闭包的一个用处就是利用JS作用域(scope)链的特性为其输出的函数提供变量引用, 把你的栗子稍加修改:

// 闭包做加法
function f1(){
    var b=1;
    function f2(a){
        return a+b;
    }
    return f2;
}

var jiafa = f1();
jiafa(10)  // 当jiafa(就是f2)运行时,它可以通过作用域链向外层作用域(f1的作用域)找到b的值, 然后返回1+11 = 11。  

这个简单的栗子要表达的主要意图就是f2通过闭包, 能够获取其定义域(f1内部)中的被保存的其他变量(b), 不管f2在哪里执行。

所以通过这个简单的栗子引申出来的一个常见应用就是绑定一个函数执行的上下文(context), 也就是能锁定this引用的对象。

function f1(){
    // 假设f1的上下文对象里有个name属性
    var self = this;    
    function f2(){
        // 即使f2被绑定到其他对象上,当f2运行时,这里能够引用的也是f1绑定的对象
        return self.name;
    }
    return f2;
}

var obj = { name: "obj", buildf2: f1 }
var f2fn = obj.buildf2();
var obj2 = {name: "obj2", f2fn: f2fn}
obj.f2fn() // 返回的是"obj"而不是"obj2"

在前端的一个应用就是锁定事件处理的this对象, 举个栗子

有一排按钮(<button>)和一个计数器(<div>), 点击任何一个都会将计数器加一, 你定义了一个函数叫addone:

如果你这么写, 并且把它作为回调函数绑定到每个按钮扭上

// 下面是伪代码,具体语法请忽略
function addone(){
    this.count++;
}
$("button").on("click", addone)

当按钮点击函数addone被执行时, 当时的this引用的是被点击的button DOM对象, 而我们想要那个<div>对象的值变化,此时就需要预先绑定那个<div>:


// 都是伪代码,只要理解意思就好了
function buildAddOne(){
    var self = $("div")
    return function addone(){
        // 这里可以是任何改变<div>里面数值的代码
        self.count++;
    }
}
var addone = buildAddOne();
// 然后再绑定到按钮上就行了
$("button").on("click", addone)

另一个场景就是异步执行的函数, 需要将当前的执行值锁定,也可以这么做:

for(var i = 0; i<10; i++){
    //这样输出的结果全是10, 因为当定时里的那个函数开始执行时,通过定义域链找到是for循环的i,而i此时已经变成10
    setTimeout(function(){
        console.log(i)
    }, 2000)
}

// 我们想要输出从1到9

for(var i = 0; i<10; i++){
    //这样会通过复制给一个局域变量达到锁定i的目的
    setTimeout( (function(local_i){
        return function(){
            console.log(local_i)
        }
    })(i), 2000)
}

这里还有别人写的一些答案:

http://stackoverflow.com/ques...

闭包的作用在于私有作用域
比如:点击list下li,弹出该li的index

list[i].onclick = function() {

alert(this.index);

}
这样是错误的。

list[i].onclick = (function(a) {

alert(a);

})(index);
这样才是可行的。

个人感觉第二个函数应该是 return f2;而不是 return f2()。然后在函数外调用,最终可以使用 f1 函数内的 b 变量,这就有闭包的意思了

javascript函数对象内部不仅包含函数代码逻辑,还包含当前的作用域链。函数之间可以通过作用域链关联起来,函数体内部的变量可以保存在函数作用域内这是闭包。第一个只不过返回了个内部变量。并没有涉及到作用域链,通过作用域链关联函数才是js闭包作用关键所在。

var scope = "global scope"; //全局变量
function checkscope() {     
  var scope = "local scope"; //局部变量
  function f() {return scope;} //在作用域中返回某个值
  return  f();
}
checkscope()                 // => “global scope”

稍作改动

var scope = "global scope"; //全局变量
function checkscope() {     
  var scope = "local scope"; //局部变量
  function f() {return scope;} //在作用域中返回某个值
  return f;
}

checkscope()()        //返回值是什么?

没错就是 local scope

function f1(){

var b=1;
function f2(){
    return b;
}
return f2;

}
在这个例子中,内部函数使用了变量b,所以变量b不会马上被回收
但是在第一个例子中的变量a会在函数执行完以后马上被回收

第一个示例中的 f1 函数中没有使用闭包,直接 return 了在 f1 函数自己内部定义的变量 a,在 f1 函数进行调用的时候,执行环境(scope)中,能够访问到全局对象(Global)和局域变量(Local)。变量 a 就是在局域变量中(Local)。

第二个示例中,f2 函数中使用了闭包,因为在函数中使用了在 f1 中定义的变量 b,这个变量 b 就会被放在闭包(Closure)中。

很明显这个示例,不适合说明闭包,因为示例2中的闭包构建毫无意义。

题主应该首先看看闭包的用途,再去研究下闭包的使用方式。

最简单的区别。在f1函数外部,可以访问f1内部的变量b

宣传栏