JavaScript一等公民函数与闭包

  • 函数与API模式
  • 函数与初识化模式
  • 函数与性能模式

关于一等公民这一身份的由来主要是相对其他语言而言,在(C/C++/Java/C#等)中,函数都是作为一个二等公民存在,你只能用语言的关键字声明一个函数然后调用它,如果需要把函数作为参数传给另一个函数,或是赋值给一个本地变量,又或是作为返回值,就需要通过函数指针(function pointer)、代理(delegate)等特殊的方式周折一番。

而在JavaScript世界中函数却是一等公民,它不仅拥有一切传统函数的使用方式(声明和调用),而且可以做到像简单值一样赋值(var func = function(){})、传参(function func(x,callback){callback();})、返回(function(){return function(){}}),这样的函数也称之为第一级函数(First-class Function)。不仅如此,JavaScript中的函数还充当了类的构造函数的作用,同时又是一个Function类的实例(instance)。这样的多重身份让JavaScript的函数变得非常重要。(参考来源:javascript语言中的一等公民-函数

  • 可以作为带有属性和方法的值以及参数进行传递
  • 函数提供局部作用域,虽然在ES6中let可以劫持一个大括号块作为独立的作用域,但还是不足以挑战函数的一等公民的身份。

函数自身可以被定义为命名函数或函数表达式,这是由语法自带的使用模式。

一、函数与API模式

函数的API模式包括:回调模式、配置对象、返回函数、Curry化,这里简单解析以下配置对象和柯里化。

配置对象:在非常多的情况下我们会通过一个函数接收不同的参数实现同一类型但不相同的具体功能,也是就是常说的配置。这时候使用多个参数就不方便实现,而是接收一个包含具体参数的对象。

柯里化详细参考(这里展示一个最终实现):JavaScript函数式编程——柯里化

 1 function Curry(fn,length){
 2     var length = length || fn.length;
 3     return function(){
 4         if(arguments.length < length){
 5             var combined = [fn].concat(Array.prototype.slice.call(arguments,0));
 6             return Curry(FixedParmasCurry.apply(this,combined),length - arguments.length);
 7         }else{
 8             return fn.apply(this,arguments);
 9         }
10     }
11 }
12 
13 function FixedParmasCurry(fn){
14     var _arg = Array.prototype.slice.call(arguments,1); //获取初始柯里化时传入的参数
15     console.log(_arg);
16     return function(){
17         var newArg = _arg.concat(Array.prototype.slice.call(arguments,0)); //拼接当前执行的参数
18     console.log(newArg);
19         return fn.apply(this, newArg);
20     }
21 }
22 function add(a,b,c,d){console.log(a + b + c + d)}

测试效果:

let addCurry = Curry(add);
addCurry(1)(2)(3)(4)
VM508:15 [1]
VM508:15 [2]
VM508:15 [3]
VM508:18 (2) [3, 4]
VM508:18 (3) [2, 3, 4]
VM508:18 (4) [1, 2, 3, 4]
VM508:22 10

当参数没有全部导入时,由新的柯里化函数包裹上一级的FixedParmasCurry的返回函数;

该函数以闭包的方式持有它对应的FixedParmasCurry作用域,在这个FixedParmasCurry作用域上有一个参数列表_arg,在参数没有全部导入时持续递归迭代这一操作。

直到参数全部导入,然后依次由后向前递归迭代执行FixedParmasCurry返回的函数实现拼接参数列表_arg,直到参数拼接完成然后调用add执行最初需要执行的任务。

二、函数与初识化模式

函数初识化模式包括:即时函数、即时对象初识化、初识化分支。

即时函数又被称为立即执行函数,这种模式主要是为了执行一个内部与其他逻辑无关的内容,只有其执行的结果才是整个程序需要的高内聚模式。

即时对象初识化,即在程序的某个环节需要生成一个对象,而不需要在程序执行前就定义的对象或者在程序执行前不能定义的对象。

初识化分支,最典型的代表就是Vue模块初识化时的声明周期中的钩子函数,通过不同的钩子函数按照既定的先后逻辑配合实现一个模块的初识化。

三、函数与性能模式

函数的性能模式包括:备忘模式、自定义模式。

备忘模式:在程序初识化时,将可能会被重复使用值使用列表、对象、闭包作用域等结构缓存下来,在需要参数值时调用结构上暴露的API获取需要的值。

自定义模式:即在一个普通的数据对象上,暴露一个基于该数据的自定义数据对象API,这样就可以减少重复的创建新的普通的数据对象。