JavaScript_JS里的函数:值和闭包

146 阅读4分钟

最近在开发一个微信小程序,语言肯定是用JavaScript。JS之前就学习过了,但很久没用,有些东西都忘了。

现在再次使用,很多东西一下子又想起来了,索性趁着这个点把想法记下来。


一、JS里函数的基本知识

先来看《HeadFirst JavaScript Programming》一书里对JS函数的解释:

我翻译如下:

如果在JavaScript之前,你已经学过较为传统的编程语言,那么你可能会觉得函数……就只是函数而已。你可以声明函数,调用函数,除此之外函数就没什么用了。

现在,你知道了JavaScript里的函数也是值类型(value)——可以被赋值给变量。一旦是值这个类型了,这就意味着我们可以把函数这个值作为另一个函数的参数传递,作为返回值return,甚至存储在数组或者对象里,就如同我们操作numbers,bool,string,objects这些值一样。

计算机科学家把能进行这些操作的值称作:一阶值(First-Class Value)。我们可以对一阶值做如下操作:

  • 赋值给变量(或者存在数组或对象里)
  • 作为参数传递给函数
  • 作为函数的返回值

因此有一阶值特性的函数就叫做一阶函数(First-Class Function)。这个特性可以说是现代编程语言的标配,JavaScript也不例外。

可以把函数存在对象里面:

可以把函数作为参数传递

二、开发中会依靠的知识:闭包

有了上面一阶值的特性,编程语言可以变得非常灵活,函数可以随意游走,在不同的领域(Domain)内穿梭。

在实际的开发中,比如微信小程序开发,通常都会有一个实际的需求——在不同的页面或者说之间可以共享各自的值。比如在这个类里进行的逻辑操作,会在执行过程中使用到另一个类的里面的值。这时候就需要依靠闭包(Closure)了。

略过原理,直接说如何用。

首先把函数作为参数传递:

home.getBannerData((data) => {
      that.setData({
        bannerArr: data,
      });
    });

然后在getBannerData()里,早在定义的时候就把这个函数参数用在哪里给安排好了:

getBannerData(callback){
        var that=this;
        var param={
            url: 'banner/1',

            sCallback:function(data){
                data=data.items;
                callback && callback(data); // 在这里执行这个参数函数
            }
        };
        this.request(param);
    }

值得注意的是,这里的参数函数是被放在对象的函数value里执行。参数函数callback所在的对象又被作为函数的参数传递了。这里就可以看出有一阶值特性的编程语言的灵活性。

最后param对象的sCallback这个key被调用,key对应的函数value被执行:

request(params, noRefetch) {
    var that = this,
    
    ...略...
    
    wx.request({
      url: url,
      data: params.data,
      method: params.type,
      header: {
        ...略...
      },
      success: function(res) {
        var code = res.statusCode.toString();
        var startChar = code.charAt(0);
        if (startChar == '2') {
          params.sCallback && params.sCallback(res.data); // 被执行
        }
    ...略...

被执行的函数会回到之前定义的地方执行函数体内的代码,即:

sCallback:function(data){
                data=data.items;
                callback && callback(data); // 回到这执行
            }

最关键的步骤来了,params.sCallback && params.sCallback(res.data);,这个res.data是在这个领域(Domain)内的值,但是现在被回传给了上一个领域,也就是说定义这个函数的地方sCallback:function(data),这个data参数现在的值则是上个领域的res.data,这也就达成了领域之间的值共享。

然后执行callback && callback(data)这句时,也是回到定义它的地方执行,同时也把res.data这个值传了过去。

home.getBannerData((data) => {
      that.setData({
        bannerArr: data,
      });
    });

在回来执行这个函数体的时候,getBannerData((data)里的data现在的值就是res.data了,也就是在这个领域里也用到了这个值。最后再通过微信小程序的setData()函数,把res.data这个值赋给这个界面。

三、总结

通过函数的传递,然后执行函数时,又回到之前定义的地方,同时还可以顺带把不同领域(Domain)里原本不共通的值传递共享,这就是闭包,在JS里这样的函数也叫回调函数。

这样类之间可以传递数据。在前端开发中,直接达成的效果就是,在页面跳转时,不同页面间的数据可以传递共享了。