前言
JavaScript 有很多有技巧的函数,这篇文章是我自己的一个记录。
链式调用
看一个例子吧,我们要实现一个函数 fun
,它有以下功能:1
fun(1).add(1).min(2).num // 0
这是一个很典型的例子,用到了链式调用,其核心就是返回自己,即 return this
,那么我们来实现这个函数吧:1
2
3
4
5
6
7
8
9
10
11function fun(num){
this.num = num;
this.add = function(num){
this.num+=num;
return this; // 核心
}
this.min = function (num){
this.num-=num;
return this; // 核心
}
}
然后我们要怎么用这个函数呢?如果我们直接链式调用:1
2fun(1).add(1).min(2);
// Uncaught TypeError: Cannot read property 'add' of undefined
只有对象才能链式调用,jquery的 $
其实是返回一个对象:1
2
3
4
5
6
7
8var obj = {
a:{
b:{
fun :function(){console.log('b');}
}
}
}
obj.a.b.fun(); // b
既然如此,那么我们就 new
一下:1
2
3
4
5
6
7
8
9
10
11
12
13function fun(num){
this.num = num;
this.add = function(num){
this.num+=num;
return this; // 核心
}
this.min = function (num){
this.num-=num;
return this; // 核心
}
}
var fun = new fun(1);
fun.add(1).min(2).num; // 0
这样和我们一开始 fun(1).add(1).min(2).num
的调用方式差了一点,既然是要用对象,那我们用一个函数包起来不就行了嘛:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function Fun(num){
this.num = num;
this.add = function(num){
this.num+=num;
return this; // 核心
}
this.min = function (num){
this.num-=num;
return this; // 核心
}
}
function fun(num){
return new Fun(num);
}
fun(1).add(1).min(2).num; // 0
这就是完整版的代码了。
compose
还是来看一道题 :1
2
3
4实现一个 compose 函数,它接受任意多个函数作为参数(这些函数都只接受一个参数),然后 compose 返回的也是一个函数,达到以下的效果:
const operate = compose(div2, mul3, add1, add1)
operate(0) // => 相当于 div2(mul3(add1(add1(0))))
operate(2) // => 相当于 div2(mul3(add1(add1(2))))
我们直接看怎么实现的:1
2
3
4
5
6
7const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
var add1 = x => x+1;
var mul3 = x=> x*3;
var div2 = x=> x/2;
var operate = compose(div2,mul3,add1,add1);
operate(0); // 3
operate(2); // 6
使用 Array.reduce()
和 ES6 的 rest
参数,执行从右向左的函数组合。最后一个 (最右边) 的函数可以接受一个或多个参数,其余的函数必须是一元的。
如果觉得很难看懂的话,我们把箭头函数改成 function
:1
2
3
4
5
6
7
8
9
10
11
12var compose2 = function (...fns){
return fns.reduce(function (f,g){
return function(...args){
return f(g(...args));
}
})
}
var add1 = x => x+1;
var mul3 = x=> x*3;
var div2 = x=> x/2;
var operate = compose(div2,mul3,add1,add1);
operate(0); // 3