JavaScript学习笔记(高阶函数)

function add(x,y,f){
	return f(x) + f(y);
}
//将Math.abs作为f传入add函数
var x = add(-5,6,Math.abs);
console.log('add:'+x);

map/reduce

如果我们想把一个函数f(x)=X2作用在一个数组[1,2,3,4,5,6]中,那么要怎么实现呢?
首先先用传统的方法来实现

//定义一个函数 
var f  = function(x){
	return  x * x;
}
var arr = [1,2,3,4,5,6];
var result = [];
for (var i = 0; i < arr.length; i++) {
	//将调用函数的结果push到新的数组中
	result.push(f(i));
}
//遍历结果数组
console.log('传统方式:'+result);

在这里插入图片描述
由于map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入到我们自己的数组中,

//定义一个函数 
function pow(x){
	return x * x;
}
var arr = [1,2,3,4,5,6];
var result = arr.map(pow);
console.log('map方式:'+result);


我们这样做一行就搞定了,是不是特别的方便!当然我们也可以有其他的功能,比如:
将Array中的所有数字转为字符串:

var arr = [1,2,3,4,5,6];
console.log(arr.map(String));


使用map将字符串变成整数

var arr=['1','2','3'];
var r;
r = arr.map(Number);

reduce

再看reduce的用法,Array的reduce()把一个函数作用在这个Array的【x1,x2,x3…】上,这个函数必须接收两个参数.
比如对一个Array求和,就可以用reduce实现:

var arr = [1,2,3,4,5,6];
console.log(arr.reduce(function(x,y){
	return x + y;
}));


要把[1,2,3,4,5]变换成整数12345,reduce()也能派上用场:

filter

filter是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素

和map()类似,Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
例如:在一个Array中,删掉偶数,只保留奇数,可以写:

var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function(x){
    return x % 2 !== 0;
});
console.log(r);


那么把一个Array中的空字符串删除,可以写成:

var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function(s){
    return s && s.trim();
});
console.log(r);


由此可以看出filter()这个高阶函数,关键在于正确实现一个“筛选”函数

回调函数

filter()接收的回调函数,其实可以有多个参数 ,通常我们仅使用 第一个参数 表示元素的位置和数组本身:

var arr =['a','b','c'];
/**
 * element 数组中的目标元素
 * index 数组中的元素的索引
 * index 整个数组
 */
var r = arr.filter(function(element,index,self){
    console.log(element);
    console.log(index);
    console.log(self);
    return true;
});


利用filter,可以巧妙的 去除Array的重复元素:

var 
r,arr = ['apply','strawberry','banana','pear','apply','orange','orange','strawberry'];
r = arr.filter(function(element,index,self){
	//数组元素对应的目标元素和数组中索引相同时就返回,这样就达到了去掉重复项
    return self.indexOf(element) == index;
});
console.log(r.toString());

sort

排序算法
排序也是程序中经常用到的算法,无论使用冒泡排序还是快速,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果字符串或者两个对象呢?直接 比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。通常规定,对于两个元素x和y,如果认为x<y,则返回-1,如果认为x == y,则返回0,如果认为x>y,则返回1,这样,排序算法就不用关心具体的比较过程,而是根据比较结果的直接排序。
JavaScript的Array的sort()方法就是使用排序的,但是排序结果可能让你大吃一惊:

var arr = [1,34,6,0];
console.log(arr.sort());


我们可以这样写排序

var arr = [1,34,6,0];
// console.log(arr.sort());
arr.sort(function(x,y){
    if(x < y){
        return -1;
    }
    if(x > y){
        return 1;
    }
    return 0;
});
console.log(arr);


倒序也是一样的原理:

var arr = [1,34,6,0];
// console.log(arr.sort());
arr.sort(function(x,y){
    if(x > y){
        return -1;
    }
    if(x < y){
        return 1;
    }
    return 0;
});
console.log(arr);


默认情况下,对字符串排序,是按照ASCII的大小比较的,现在,我们提出排序应该忽略大小写,按照字母排序,要实现这个算法,不必对现在代码在加改动,只要我们能定义出忽略大小写的比较算法就可以实现排序了:

var arr = ['Google', 'apple', 'Microsoft'];
arr.sort(function(s1,s2){
    //将字母转换为大写
    x1 = s1.toUpperCase();
    x2 = s2.toUpperCase();
    if(x1 < x2){
        return -1;
    }
    if(x1 > x2){
        return 1;
    }
    return 0;
});
console.log(arr);

在这里插入图片描述
这样就排序成功了!

Array

对于数组,除了map()、reduce、filter()、sort()这些方法可以传入一个函数外,Array对象还提供了很多非常实用的高阶函数。

every

every()方法可以判断数组的所有元素是否满足测试条件
例如:
判断当前数组中的元素长度是否大于0

var arr = ['Apple','pear','orange'];
console.log(arr.every(function (s){
    return s.length > 0;
}));//true,每个元素都满足s.length>0
console.log(arr.every(function (s){
    return   s.toLowerCase() === s;
}));//false,因为不是每个元素都全部是小写

find

find()方法用于查找符合条件的第一个元素,如果找到 了,返回这个元素,否则,返回undefined;

var arr = ['Apple','pear','orange','HKK'];
console.log(arr.find(function (s){
    return s.toLowerCase() === s;
}));//'pear',因为pear全部是小写
console.log(arr.find(function (s){
    return s.toUpperCase() === s;
}));//'HKK',因为HKK全部是大写的

findIndex

var arr = ['Apple','pear','orange','HKK'];
console.log(arr.findIndex(function (s){
    return s.toLowerCase() === s;
}));//1.因为'pear'的索引是1

console.log(arr.findIndex(function (s) {
    return s.toUpperCase() === s;
}));//3,因为'HKK'的索引是3

forEach

forEach()和map()类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。forEach()常用于遍历数组,因此,传入的函数不需要返回值:

var arr = ['Apple','pear','orange','HKK'];
arr.forEach(console.log);//依次打印 每个元素

闭包

函数作为返回值

//我们不是立刻得到进行求和,而是在后面的代码中使用,就先保存求和的函数!
function lazy_sum(arr) {  
    //定义一个函数用于求和
    var sum = function(){  
        return arr.reduce(function (x,y) {  
            return x + y;
        });
    }
    return sum;
}
//调用lazy_sum时其实是[Function: sum]函数
var f  = lazy_sum([1,2,3,4,5,6,7,8,9,10]);
//这里才是真正的调用
console.log(f());


总结:在上面这个例子中,我们在函数 lazy_sum中又定义了一个函数sum,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时 ,相关参数和变量都保存在返回的函数 中,这种称为"闭包(Closure)"的程序结构拥有极大的威力。

这两次的调用每次都会返回一个新的函数,虽然传入的是相同 的参数 ,但是调用的结果不互相影响!

闭包

注意到返回的函数在其定义内部引用了局部变量arr,所以,当现代战争函数 返回一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可没有那么容易。
另一个需要注意的问题是,返回的函数 并没有立即执行,而是直到调用了f()才执行,我们来看一个例子:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章