JavaScript: 零基础轻松学闭包(2)

注:本人发布的所有文章均为原创,未经作者许可,切勿转载,谢谢。

本文面向初学者,大神轻喷。

好了,开始吧。

上一节 JavaScript: 零基础轻松学闭包(1)中,我们对闭包的原理进行了讲解,这一节会说很多实战性的东西了,可能会有点难度,你准备好了吗?

1. 如何将私有数据暴露出去

还记得在上一节中,有这样一个例子么?

var test = function(){
    var i = 10;
}

function test2(){
    alert(i);
}

test2();

函数 test 和 test2 各自形成一个闭包,两个闭包之间无法访问对方的私有数据。比如,在 test 中定义的变量,在 test2 里面是无法直接访问到的。

那么问题来了, 当然,这边和挖掘机没关系。这里的问题是,有没有什么办法让 test2 可以访问到其他闭包中的私有变量呢?

办法当然是有的,最直接的想法就是,大不了我定义一个全局变量,在 test 中将私有数据赋给全局变量,然后在 test2 里面就能访问到了。

是的,因为两个函数共同享有一个全局作用域,所以这个办法确实可行。我在很多项目里也的确看到很多人就是这么做的。

那么,有没有一种更好的方法呢?要知道,全局作用域是一个比较敏感的地方,一不小心就会出现变量名重复的问题。顺便说一句,在全局作用域中,尽量不要使用诸如 temp , a , b , c 这一类的大众化变量。

于是,这就牵扯到返回值的相关知识了,你在C语言的教材中肯定见惯了类似于这样的代码

int sum(int a,int b)
{
    return a + b;
}

int all = sum(3,5);

这是一个简单的求和函数,很多人慢慢地养成了这样一个观念,就是函数的返回值就是一个字面值,要么是数字类型,要么是布尔类型,或者是字符串。

在很多强类型的语言,诸如 Java,C,C++, 确实如此。但是 return 在 JavaScript 中却大有来头。

在上一节已经说明了,js 的函数也是一种数据类型,你可以把函数看成是和int , float , double 一样的东西。

那么,既然int可以当做函数的参数或者返回值,函数当然也可以!

请看下面两句话:

在js中

  • 如果函数被当做参数传进去了,它就是所谓的回调函数。
  • 如果函数被当做返回值return出去了,它就是把一个闭包return出去了。

这一章不讲回调函数,如果你不清楚啥叫回调函数,可以去看看这个小例子: (浅谈js回调函数

还是上面的那个例子,我们希望在 test2 中可以访问到 test 里面的变量,可以这样做:

var test = function(){
    var i = 10;
    /* 定义一个函数将变量i暴露出去  */
    var get = function(){
        return i ;
    }
    return get; //将获得i的函数暴露出去
}

function test2(){
    
    var fn= test();//接收test暴露出来的函数
    alert(fn()); //获得test中的私有数据
}

test2();

Paste_Image.png

test 函数中的 get 方法是一个内部函数,它自己也形成了一个闭包, test 是他的父级作用域,因此它可以获取i的值。

i 进入 get 方法的闭包,被包了起来,然后最终被返回了出去。

而对于 test2 来说,是可以访问到 test函数的,因此可以调用并执行 test 函数,从而获取其返回值。

你可能会说,我直接在test中把i给return出去就好了嘛,干嘛这么麻烦。

是的,言之有道理。

可是,如果我要访问 test 中多个私有数据咋办捏?

这下你可明白了吧!

现在,我们给出关于闭包的第二个注解: (第一个注解在上一节)

从应用的角度来看,闭包可以将函数或者对象的私有数据暴露出去,而不影响全局作用域。

Paste_Image.png

通过这张图,是不是好理解一些了呢?我们这一节单说函数里的私有数据。

2. 将私有数据包装成json对象

刚才的例子说明,在js中,return出去的可以是基本数据类型,也可以是函数类型。

其实,JavaScript是一种基于对象的语言,也有对象的概念,所以,我们可以把你需要的东西包裹成一个对象返回出去!

上代码:

var test = function(){
    var apple = '苹果';
    var pear = '梨子';
    /* 定义一个函数将水果暴露出去  */
    var getFruit = {
        apple : apple ,
        pear : pear
    }
   
    return getFruit; //将获得i的函数暴露出去
}

function test2(){
    
    var getFruit = test();//接收test暴露出来的函数
    
    console.log(getFruit);
}

test2();

像这样用 { } 括起来的东西就是一个js对象,也就是所谓json。你可能经常会听到json这个词,觉得还挺高大上的。其实它就是一个用 { } 包起来的数据而已。

里面是键值对的形式,非常类似于Java里面的HashMap。

在这个例子中,我们可以直接把需要暴露的私有数据用一个 { } 包起来,构成一个json对象return出去就可以啦。

因为是 js 对象,alert 不能看到里面的具体内容,所以我们使用 console.log() ,结果如下:

Paste_Image.png

展开后:

Paste_Image.png

这样是不是也可以了?多出来的 proto 是原型链,以后会讲到。

3. 我们来做一个紫金葫芦

大家都还记得西游记里孙悟空用遮天的把戏骗来的紫金葫芦吗,只要你拿着这个葫芦,叫一声别人的名字,如果答应了,别人就会被吸进去。

OK,这个紫金葫芦里面不正如一个闭包吗?

对不对嘛,所以,我们用闭包的知识来做一个好玩的东西吧。

<body>
    <div id='box' style='width:50px;height:50px;background:#333;color:#fff;text-align:center;line-height:50px'>小妖</div>
</body>

Paste_Image.png

紫金葫芦里面的源码大概是这样的:

var 紫金葫芦 = function(id){
    var domElement = document.getElementById(id);
    
    var returnObject = {

        domElement : domElement ,

        backgroundColor : function(color){
            domElement.style.backgroundColor = color;
        },

        click : function(fn){
            domElement.onclick = fn;
        }
    };
    
    return returnObject;
}

注:我纯粹是为了看起来方便而采用中文定义变量,在实际开发中,千万不要使用中文变量。

我们在返回出去的对象上加了三个东西:

1.domElement 你传进来一个id,我就用 document.getElementById 来包一下,得到一个dom元素,最终要操作的也就是这个dom元素。也就是说:

var box1 = 紫金葫芦('box').domElement;
var box2 = document.getElementById('box');
alert(box1 === box2);

Paste_Image.png

他们是一个东西,一样的。

紫金葫芦('box');

这行代码一旦执行,紫金葫芦就会返回 returnObject 对象,也就是说。我们喊一声 “box”,那个id为box的小妖一答应,就被装进来了,然后我们可以对它为所欲为!

比如,给它换一个背景色:

2.backgroundColor 给元素添加背景色的方法

var box = 紫金葫芦('box');
box.backgroundColor('red');

Paste_Image.png

3.click 给元素添加点击事件,需要传入一个回调函数

var box = 紫金葫芦('box');
box.click(function(){
    alert('就没人吐槽这个无聊的作者么,小妖也有尊严的好么,啊喂!!');
});

结果:

click.gif

也许你已经发现了,这些方法是不是和jQuery有点类似呢?

本章结束 ...

剽悍一小兔,电气自动化毕业。 参加工作后对计算机感兴趣,深知初学编程之艰辛。 希望将自己所学记录下来,给初学者一点帮助。

免责声明: 博客中所有的图片素材均来自百度搜索,仅供学习交流,如有问题请联系我,侵立删,谢谢。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青玉伏案

设计模式(十):从电影院中认识"迭代器模式"(Iterator Pattern)

上篇博客我们从醋溜土豆丝与清炒苦瓜中认识了“模板方法模式”,那么在今天这篇博客中我们要从电影院中来认识"迭代器模式"(Iterator Pattern)。“迭代...

19810
来自专栏Python数据科学

如何用Python递归地思考问题?

递归是一个很经典的算法,在实际中应用广泛,也是面试中常常会提到的问题。本文就递归算法介绍如何在Python中实现递归的思想,以及递归在Python中使用时的一些...

6316
来自专栏鹅厂优文

Python 工匠:善用变量来改善代码质量

我一直觉得编程某种意义上是一门『手艺』,因为优雅而高效的代码,就如同完美的手工艺品一样让人赏心悦目。

99310
来自专栏Python小屋

Python正则表达式中的贪心模式和非贪心模式

声明:最近发现有人利用我在百度云盘里免费分享的127课Python视频盈利,并声称获得我的授权。在此,我声明,文末百度云盘里的Python视频是免费的,不会授权...

2827
来自专栏take time, save time

你所能用到的数据结构(八)

十一、不能被应用的理论不是好研究 前面介绍了堆栈的一些小小的理论模型,那么这样一个东西有什么作用呢?实际中不可能有那么一辆停在站台前方堵死的火车的,即使有,也...

2704
来自专栏ACM算法日常

最高的牛Tallest Cow(前缀和)- POJ 3263

FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. E...

1111
来自专栏企鹅号快讯

Python模块知识2:时间日期日历模块Time、Datetime、Calendar

1、time模块 时间为什么从1970年开始:因为Linux系统那一年开始使用;通常由以下几种方式表示时间: 时间戳:1970年1月1日之后的秒,即:time....

2545
来自专栏C语言及其他语言

[每日一题]大、小写问题

题目描述 输入一串字符,将其中的大写变成小写,若不为大写则原样输出 输入 任意字符串(长度在100以内)以回车表示输入结束 输出 将其中的大写 输出相应的小写,...

2906
来自专栏技术墨客

Java函数式开发——优雅的Optional空指针处理

    在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员。在我们逼格闪闪的java码字符生涯中,每天都会遇到各种nu...

1162
来自专栏web前端教室

=>,Es6箭头符号的前世今生

看代码能看错行,一看书就头疼且双眼流泪,没办法啊,都是娘胎里带出来的毛病,能看点是点吧。es6这种东西,虽然有一些语法糖,但毕竟也是新东西啊,得学。不学就落后,...

21610

扫码关注云+社区

领取腾讯云代金券