猫史档案馆


【js进阶教程】闭包怎么用?可乐的JavaScript进阶教程(1)--了解闭包、闭包的使用

用户:爱探险的可乐呀爱探险的可乐呀查看:6 回复:13 评论:6 创建时间:2021-02-16T19:47:03


center_image

哎嘿大家好啊ヾ(≧▽≦*)o

我是可乐~~~

今天咱们来一期JavaScript进阶教程——闭包

(不会吧不会吧不会有人说闭包是基础吧)

好的废话不多说直接开始教程——

-----------------------------------------------------------------------------------------------

1.js的变量作用域

要想理解闭包这个东东,就要先理解JavaScript的变量作用域

js中的变量分为两种:

全局变量局部变量

js中规定,函数中可以直接读取全局变量

举个栗子🌰

var a = 999; //定义一个全局变量
function yiGeHanShu() { //定义一个函数,函数名可以随便起,毕竟这只是个例子()
    console.log(a); //输出全局变量a
}
yiGeHanShu(); //运行结果:999

另外呢

在函数外部无法读取函数内的局部变量

再举个栗子🌰

function yiGeHanShu() {
    var a = 999;
}
console.log(a); //运行结果:报错

这就是JavaScript特有的“链式作用域”,

在这一个作用域下面的作用域能读取这个作用域的变量 但是这个作用域不能读取下一个作用域的变量()

有亿点绕口是不是 这段需要慢慢琢磨哦()

那怎么从外部读取局部变量呢?

闭包就出来了——

-----------------------------------------------------------------------------------------------

2.简单闭包的定义和使用

由于各种各样的原因

我们要读取一个函数的内部变量

但是 正常情况下,我们是做不到哒

所以 有请闭包上场()

再再举个栗子🌰:

function a() {
    var a = 999;
    function b() {
        console.log(a);
    }
}

这样定义函数的话,函数b()就在函数a()内部

这个时候

函数a()这个作用域的所有局部变量,对函数b()这个下面的作用域都是可读取的

既然b()可读取a()的局部变量,那把b()作为a()的返回值不就行了吗?!

function a() {
    var a = 999;
    function b() {
        console.log(a);
    }
    return b;
}
var c = a(); //这时c是a()的返回值,也就是一个函数,我们在接下来调用它
c(); //运行结果:999

一个简单的闭包就完成辽~

或者 还有一种写法

function a() {
    lan_de_xie
    return b;
}
a()();

a()()又是什么东东呢?

前面的a()表示函数调用,返回b这个函数

然后把前面的a()看成一个整体,再调用一次(这时调用的是b()这个函数)

运行结果就是999~

上个例子中,b()这个函数就是闭包

那闭包的概念是什么呢?

欢迎在评论区打出你的答案()

我的理解是:

闭包函数就是能够读取函数内部变量的函数

因此可以简单理解为:

函数里的函数()

好家伙()这不就是套娃嘛()

-----------------------------------------------------------------------------------------------

3.闭包的用途

闭包这东东有个好处

就是函数中的变量都会保留在内存中

那我们不就可以做一个计数器吗?

开整!

普通思路

如果我们不用闭包,用普通的思路,那么代码将会是这样的

var counter = 0;
function add() {
    counter++;
}
add();
add();
add();
//此时counter为3

诶这个时候你就有可能会说了

“可乐这效果可以啊 为啥要用闭包啊”

那你想一想 你可以手动控制counter作弊啊是不是

lan_de_xie
add();
counter += 27346198746526516734;
//此时counter为27346198746526516735

那怎么防止这种作(dong)弊(shou)行为呢?

这就需要用到闭包了

闭包思路

function add() {
    var counter = 0;
    return function () {
        return ++counter;
    }
}
var a = add();
a();
a();
a();
//此处counter为3

为什么是++counter呢?

这就要涉及到我们刚学js就知道的a++和++a的区别()

a++:运算过程中先执行a表达式,之后再执行自增运算。

++a:运算过程中先执行自减运算,之后再运行a表达式。

度娘拿过来参考的,大家看一下就可以了

如果用counter++,那运行结果就是3

那为什么不用add()()呢?

因为用add()()的话每次函数就会重新运行一遍 也就是counter会清零

所以用变量储存add()的值

然后再调用add()函数返回的函数

上面这段话还是得好好琢磨()

-----------------------------------------------------------------------------------------------

4.思考题()

如果你能理解下面两段代码的运行结果,应该算理解闭包的运行机制了吧()

tips:代码来自阮一峰老师的博客

1.

//此段代码为前端 请勿用node运行~
var n = "我是窗口";
var obj = {
    name: "我是对象",
    getName: () => {
        return () => {
            return this.name;
        };
    },
}
alert(obj.getName()());

2.

//此段代码为前端 请勿用node运行~
var n = "我是窗口";
var obj = {
    name: "我是对象",
    getName: () => {
        var that = this;
        return () => {
            return that.name;
        };
    },
}
alert(obj.getName()());

好了这就是这期教程的全部内容了

我是可乐

我们下期再见~(~ ̄▽ ̄)~


回复

上一页1 页 / 共 1下一页
爱探险的可乐呀爱探险的可乐呀

例子的代码有个小彩蛋 看看谁能找到

点赞0


评论


爱探险的可乐呀爱探险的可乐呀

点赞0


评论


AlcalaAlcala

dd

点赞0


评论


BSS梅者如西BSS梅者如西

不错

点赞0


评论


白篮白篮

点赞0


评论


AlcalaAlcala

点赞0


评论


BSS梅者如西BSS梅者如西

补充个东西:

就是本文第1、2段代码所用的变量/函数的命名方法:

(小)驼峰命名法,通常用于单词过多或者中文设置变量。

首先比如说:Football Club Barcelona改成变量就是footballClubBarcelona;

再比如说:巴萨改成变量就是baSa。

具体用法就是把单词/音节连一起把音节的首字母大写,再把新变量名的首字母变小写

另外还有一个跟(小)驼峰命名法相似的就是下划线命名法。

举个同样的例子:Football Club Barcelona改成变量就是Football_Club_Barcelona;

巴萨改成变量就是Ba_Sa。

具体用法是把单词/音节的中间隔一个_。

以上两个用法都用于普通变量,其他类型的变量还有其他用法。

(求置顶)

点赞0


评论


没尾巴的鲸鱼没尾巴的鲸鱼

其实把alert改成console.log就可以在node.js运行

点赞1


评论


卫道士32_32*2没了卫道士32_32*2没了

返回对象

center_image

点赞0


评论


爱探险的可乐呀爱探险的可乐呀

才发现有点部分打错了

第三部分

++a:运算过程中先执行自运算,之后再运行a表达式。

是自加,粘贴忘记改了()

-----------------------------------------------------------------

如果用counter++,那运行结果就是2

因为第一个a()的返回值为0

-----------------------------------------------------------------

思考题

1.

//此段代码为前端 请勿用node运行~
var name = "我是窗口";
var obj = {
    name: "我是对象",
    getName: () => {
        return () => {
            return this.name;
        };
    },
}
alert(obj.getName()());

2.

//此段代码为前端 请勿用node运行~
var name = "我是窗口";
var obj = {
    name: "我是对象",
    getName: () => {
        var that = this;
        return () => {
            return that.name;
        };
    },
}
alert(obj.getName()());

思考题涉及到了一个很重要的知识点:this关键字

点赞0


评论


爱探险的可乐呀爱探险的可乐呀

思考题是太难了吗没人做()

点赞0


评论


爱探险的可乐呀爱探险的可乐呀

点赞0


评论


yee剑走天下yee剑走天下

ddd)

点赞0


评论