2025年3月21日 星期五 甲辰(龙)年 月廿 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

JS高阶函数精讲

时间:03-07来源:作者:点击数:94

高阶函数也称算子(运算符)或泛函。作为函数式编程最显著的特征,高阶函数是对函数运算进行进一步的抽象。高阶函数的形式应至少满足下列条件之一:

  • 函数可以作为函数被传入,也称为回调函数,如函数合成运算。
  • 可以返回函数作为输出,如函数柯里化运算。

JS回调函数

把函数作为值传入另一个参数,当传入参数被调用时,就称为回调函数,即异步调用已绑定的函数。例如,事件处理函数、定时器中的回调函数、异步请求中的回调函数、replace 方法中的替换函数、数组迭代中的回调函数(sort、map、forEach、filter、some、every、reduce 和 reduceRight 等),都是回调函数的不同应用形式。下面仅举两个示例,演示回调函数的应用。

示例1

下面代码根据日期对对象进行排序。

  • //声明3个对象,每个对象都有属性id和date
  • var a = {id : 1, date : new Date(2019,3,12)},
  •     b = {id : 2, date : new Date(2019,1,14)},
  •     c = {id : 3, date : new Date(2019,2,26)};
  • var arr = [a,b,c];
  • arr.sort(function(x,y){
  •     return x.date-y.date;
  • });
  • for (var i = 0; i < arr.length; i++) {
  • console.log(arr[i].id + " " + arr[i].date.toLocaleString());
  • }

输出结果:

2 2019 年 2 月 14 日 0:00:00
3 2019 年 3 月 26 日 0:00:00
1 2019 年 4 月 12 日 0:00:00

在数组排序的时候,会迭代数组每个元素,并逐一调用回调函数 function(x,y) {return x.date - y.date}。

示例2

在《JS map()》一节中我们曾介绍过数组的 map 方法,实际上很多函数式编程语言均有此函数。其语法格式为:

map(array,func)

map 表达式将 func 函数作用于 array 的每一个元素,并返回一个新的 array。

下面使用 JavaScript 实现 map(array,func) 表达式运算。

  • function map(array,func) {
  • var res = [];
  • for (var i in array) {
  • res.push(func(array[i]));
  • }
  • return res;
  • }
  • console.log(map([1,3,5,7,8], function (n) { //返回元素值的平方
  • return n * n;
  • })); //1,9,25,49,64
  • console.log(map(["one", "two", "three", "four"], function(item) { //返回首字母大写
  • return item[0].toUpperCase() + item.slice(1).toLowerCase();
  • })); //One,Two,Three,Four

两次调用 map,却得到了截然不同的结果,是因为 map 的参数本身已经进行了一次抽象,map 函数做的是第二次抽象。注意:高阶的“阶”可以理解为抽象的层次。

JS 函数既可以作为参数传入函数内部,也可以作为返回值 return 到函数外部,具体应用场景包括:

由于篇幅有限,本节只介绍前面三种应用场景,其它场景请猛击链接查看。

JS单例模式

单例就是保证一个类只有一个实例。实现方法:先判断实例是否存在,如果存在则直接返回,否则就创建实例再返回。

单例模式可以确保一个类型只有一个实例对象。在 JavaScript 中,单例可以作为一个命名空间,提供一个唯一的访问点来访问该对象。单例模式封装代码如下:

  • var getSingle = function (fn) {
  • var ret;
  • return function () {
  • return ret || (ret = fn.apply(this, arguments));
  • };
  • };

示例1

在脚本中定义 XMLHttpRequest 对象。由于一个页面可能需要多次创建异步请求对象,使用单例模式封装之后,就不用重复创建实例对象,共用一个即可。

  • function XHR () { //定义XMLHttpRequest 对象
  • return new XMLHttpRequest();
  • }
  • var xhr = getSingle(XHR); //封装XHR实例
  • var a = xhr(); //实例1
  • var b = xhr(); //实例2
  • console.log(a === b); //true,说明这两个实例实际上相同

示例2

可以限定函数仅能调用一次,避免重复调用,这在事件处理函数中非常有用。

  • <button>仅能点击一次</button>
  • <script>
  • function getSingle (fn) {
  • var ret;
  • return function () {
  • return ret || (ret = fn.apply(this,arguments));
  • };
  • };
  • var f = function () { console.log(this.nodeName); } //事件处理函数
  • document.getElementsByTagName("button")[0].onclick = getSingle(f);
  • </script>

JS实现 AOP

AOP(面向切面编程)就是把一些与业务逻辑模块无关的功能抽离出来,如日志统计、安全控制、异常处理等,然后通过“动态织入”的方式掺入业务逻辑模块中。这样设计的好处是:首先可以保证业务逻辑模块的纯净和高内聚性;其次可以方便地复用日志统计等功能模块。

示例

在 JavaScript 中实现 AOP,一般是把一个函数“动态织入”到另外一个函数中。具体的实现方法有很多,下面通过扩展 Function.prototype 方法实现 AOP。

  • Function.prototype.before = function (beforefn) {
  •     var __self = this//保存原函数的引用
  •     return function () //返回包含了原函数和新函数的“代理”函数
  •         beforefn.apply(this, arguments);  //执行新函数
  •         return __self.apply(this, arguments);  //执行原函数
  •     }
  • };
  • Function.prototype.after = function (afterfn) {
  •     var __self = this//保存原函数的引用
  •     return function () //返回包含了原函数和新函数的“代理”函数
  •        var ret = __self.apply(this,arguments);  //执行原函数
  •         afterfn.apply(this, arguments);  //执行新函数,修正this
  •         return ret;
  •     }
  • };
  • var func = function (){
  •     console.log(2);
  • };
  • func = func.before(function () {
  •     console.log(1);
  • }).after(function () {
  •     console.log(3)
  • });
  • func();  //按顺序输出1,2,3

类型检测

本节利用 JavaScript 高阶函数特性来重新设计 typeOf() 函数,并提供单项类型判断函数。

【实现代码】

  • function typeOf(obj) { //类型检测函数,返回字符串表示
  • var str = Object.prototype.toString.call(obj);
  • return str.match(/\[object(.*?)\]/)[1].toLowerCase();
  • };
  • ['null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp'].forEach(function (t) { //类型判断,返回布尔值
  • typeOf['is' + t] = function (o) {
  • return typeOf(o) === t.toLowerCase();
  • };
  • });

【应用代码】

  • //类型检测
  • console.log(typeOf({})); //"object"
  • console.log(typeOf([])); //"array"
  • console.log(typeOf(0)); //"number"
  • console.log(typeOf(null)); //"null"
  • console.log(typeOf(undefined)); //"undefined"
  • console.log(typeOf(//)); //"regex"
  • console.log(typeOf(new Date())); //"date"
  • //类型判断
  • console.log(typeOf.isObject({})); //true
  • console.log(typeOf.isNumber(NaN)); //true
  • console.log(typeOf.isRegExp(true)); //false
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
上一篇:JS偏函数 下一篇:JS递归函数精讲
推荐内容
相关内容
栏目更新
栏目热门