从零开始学_JavaScript_系列(19)——js系列<6>闭包

简介: (18)闭包 ①函数内部的子函数,用到了父函数的变量,就叫做闭包。   ②可以为函数保存其执行状态,   ③其原理大概是: 首先,假如B函数在A函数的内部,则A为外部函数,B为内部函数,B可以访问A的变量(变量的作用域规定的); 然后,假如在函数内部,如果有一个return,那么在return结束前,这个函数中的变量,其值是维持不变的; 另外需要注意,不能让A函数(外部函数

(18)闭包

①函数内部的子函数,用到了父函数的变量,就叫做闭包。

 

②可以为函数保存其执行状态,

 

③其原理大概是:

首先,假如B函数在A函数的内部,则A为外部函数,B为内部函数,B可以访问A的变量(变量的作用域规定的);

然后,假如在函数内部,如果有一个return,那么在return结束前,这个函数中的变量,其值是维持不变的;

另外需要注意,不能让A函数(外部函数)执行完毕,否则状态无法保留(因为闭包的前提是A函数没有执行完毕),因此不能直接调用A函数,而是需要生成A函数return部分的一个实例。

 

因为有了这两个前提,于是两个办法:

方法一:我们可以把B函数放在A函数的return之中。return的内容是一个对象{},然后通过new生成这样一个对象,B函数成为这个对象的一个方法;

如代码:

var func = function () {
    var i = 0;
    return {
        getI: function () {
            return i;
        },
        add: function () {
           i++;
        }
    }
}
var p = new func();
p.add();
console.log(p.getI());

此时,p.add()会导致i的值增加,此时i的值变为了1。

 

 

方法二:让A函数的return部分,成为一个函数,

但不能直接操纵A函数,因为调用A函数必然会导致A函数的return执行完毕,(因为函数会执行到return结束)

因此,需要将A函数的return部分赋值给另外一个变量C,此时C是A函数return部分(要记得,这个return部分是一个函数)的一个实例(相当于一个构造函数生成一个实例)。

而B函数是这个return部分的构造函数的一个方法,因此这个生成的实例也拥有了B函数这个方法。

如代码:

var func = function () {
    var i = 0;
    return function(){
        i++;
        return i;
    }
}
var p = new func();
console.log(p());
console.log(p());

这时,p的调用会导致i加一,因此调用p,输出的值分别为1和2。

 

ps:无论是哪种方法,假如我们再new一个实例

var q = new func();

其并不会导致i的值在p和q之间共享。

 

 

④优点:

按照网易云课堂的说法,闭包可以减少内存使用,提高效率。(个人经过实测,认为没有说服性)

但是经过我实测,大部分方法和闭包差不多,比闭包慢的一个方法我后面列出。

如:

var func = function () {
    var i = 0;
    return function () {
        i++;
        return i;
    }
}
var starttime = new Date();
var p = new func();
for(var i=0;i<1000000;i++){
    p();
}
console.log(p())
console.log(new Date()-starttime);

计算一百万次,消耗时间大概10毫秒左右。

 

这是我看网易云课堂给的一个示例(我自己略有修改);

function sum(i) {
    var add = function (i) {
        i++;
        return i;
    }
    return add(i);
}
var starttime = new Date();
for (var i = 0; i < 1000000; i++) {
    sum(1);
}
console.log(sum(1));
console.log(new Date() - starttime);

其时间耗时为30毫秒左右。

但这个例子事实上返回了2次,所以我觉得不能证明闭包更快。例如,常规写法:

function sum(i) {
    i++;
    return i;
}

其耗时就和闭包差不多。我把计算量增加10倍(到一千万次),其时间和上面那个所说的比较慢的方法是差不多的(30ms左右)。

因此个人认为,应该是双重return所导致了耗时增多。

 


 

⑤闭包的利用:

假设我们有N个按钮,想点击第x按钮时,输出x。

var m = function () {
    function cli(i){
        return function(){
            console.log(i);
        }
    }
    for (var i = 1; i < 3; i++) {
        document.getElementById("test" + i).onclick = cli(i);
    }
}
m();

初始时,不输出任何变量。点击id="test1",输出1,点击id="test2",输出2。

 

假如逐个绑定,那么是不能达成这种目的的。例如:

for (var i = 1; i < 3; i++) {
    $("#test" + i).click(function () {
        console.log(i)
    });
}

并不能如我们所愿那样,点击第一个按钮便输出1,事实上,无论点哪个,输出都是3。

 


目录
相关文章
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理与实战
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理与实战
|
25天前
|
JavaScript 前端开发
js 闭包的优点和缺点
【10月更文挑战第27天】JavaScript闭包是一把双刃剑,在合理使用的情况下,它可以带来很多好处,如实现数据封装、记忆功能和模块化等;但如果不注意其缺点,如内存泄漏、变量共享和性能开销等问题,可能会导致代码出现难以调试的错误和性能问题。因此,在使用闭包时,需要谨慎权衡其优缺点,根据具体的应用场景合理地运用闭包。
106 58
|
25天前
|
缓存 JavaScript 前端开发
js 闭包
【10月更文挑战第27天】JavaScript闭包是一种强大的特性,它可以用于实现数据隐藏、记忆和缓存等功能,但在使用时也需要注意内存泄漏和变量共享等问题,以确保代码的质量和性能。
36 7
|
28天前
|
自然语言处理 JavaScript 前端开发
JavaScript闭包:解锁编程潜能,释放你的创造力
【10月更文挑战第25天】本文深入探讨了JavaScript中的闭包,包括其基本概念、创建方法和实践应用。闭包允许函数访问其定义时的作用域链,常用于数据封装、函数柯里化和模块化编程。文章还提供了闭包的最佳实践,帮助读者更好地理解和使用这一强大特性。
16 2
|
2月前
|
设计模式 JavaScript 前端开发
探索JavaScript中的闭包:从基础概念到实际应用
在本文中,我们将深入探讨JavaScript中的一个重要概念——闭包。闭包是一种强大的编程工具,它允许函数记住并访问其所在作用域的变量,即使该函数在其作用域之外被调用。通过详细解析闭包的定义、创建方法以及实际应用场景,本文旨在帮助读者不仅理解闭包的理论概念,还能在实际开发中灵活运用这一技巧。
|
2月前
|
缓存 JavaScript 前端开发
深入了解JavaScript的闭包:概念与应用
【10月更文挑战第8天】深入了解JavaScript的闭包:概念与应用
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理、应用与代码演示
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理、应用与代码演示
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript闭包:原理与应用
【10月更文挑战第11天】深入理解JavaScript闭包:原理与应用
20 0
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:概念与应用
【10月更文挑战第8天】深入理解JavaScript中的闭包:概念与应用
|
2月前
|
JavaScript 前端开发 开发者
深入理解JavaScript中的闭包:原理与应用
【10月更文挑战第8天】深入理解JavaScript中的闭包:原理与应用