闭包与高阶函数@TOC
闭包与高阶函数
事实上闭包与高阶函数在js中很常见。
1 闭包
当函数可以记住并访问所在的词法作用域时,就产生了闭包。即使函数在当前函数的作用域之外执行。
例子:
function foo() {
var a = 2
function bar() {
console.log(a)
}
return bar
}
var baz = foo() baz() // 输出: 2
1.1 利用闭包实现结果缓存
例子:
/**
* 闭包备忘函数,
* 假如add是一个很复杂的计算函数,如果每次运行,则需要消耗大量的空间和时间,利用闭包
* 特性,将之前的状态进行保存 这样就可以在第二次调用的时候,直接输出结果,而不需要重
* 新计算,则节省了空间的消耗。
* */
function add(a) {
return a + 1;
}
function memorise(fn) {
var cache = {};
return function (){
var args = Array.prototype.slice.call(arguments);
var key = JSON.stringify(args);
return cache[key] || (cache[key] = fn.apply(fn, args));
}
}
var addrs = memorise(add);
console.log(addrs(1));
console.log(addrs(2));
console.log(addrs(3));
console.log(addrs(2));
2高阶函数
2.1 函数作为参数
典型的应用比如就是回调函数。
比如:
setTimeout(function() {
console.log("这是一个回调函数");
}, 1000);
// 钩子函数
function mainFunc(callback) {
callback();
}
2.2 函数作为返回值(闭包)
function Fun() {
return function bar() {
console.log("this is a closure");
}
}
2.2.1 柯里化
柯里化(currying),又称为部分求值,是把多个参数的原函数变换成为接受单一参数的函数,并且返回一个新的函数,新函数能够接受余下的参数,最后返回同原函数一样的结果。
作用:
(1)参数复用
(2)提前返回
(3)延迟计算/运行
通用实现:
/**
* Currie 柯里化 通用实现
*/
function curryingEs5(fn) {
var rest1 = Array.prototype.slice.call(arguments); // 用来记录默认参数的参数数组
rest1.shift();
return function() {
var rest2 = Array.prototype.slice.call(arguments); // 用来记录传入的参数
return fn.apply(null, rest1.concat(rest2));
}
}
// function curryingEs6(fn, ...rest1) {
// return function(...rest2) {
// return fn.apply(null, rest1.concat(rest2));
// }
// }
function sayHello(name, age, hobby) {
console.log("my name is " + name + " my age is " + age + " years old and my hobby is " + hobby);
}
var curryingTest = curryingEs5(sayHello, "xaiogang");
curryingTest("26", "play pingpong ball");
2.2.2 反柯里化
扩大适用范围,创建一个应用范围更加广的函数,使得原本只有特定对象才适用的方法,扩展到更多的对象。
例子:
function unCurryingEs5(fn) {
return function (tar) {
var rest = Array.prototype.slice.call(arguments);
rest.shift();
return fn.apply(tar, rest);
}
}
var push = unCurryingEs5(Array.prototype.push);
function exePush() {
push(arguments, 4);
console.log(arguments);
}
exePush(1, 2, 3);
偏函数
偏函数是创建一个调用另外一部分的函数,函数可以根据传入的参数来生成一个真正执行的函数。其本身不包含我们真正需要的逻辑代码,只是根据传入的参数返回其他的函数,返回的函数中才含有真正的处理逻辑。
/**
* 偏函数
*/
var isType = function(type) {
return function(obj) {
return Object.prototype.toString.call(obj) === `[object ${type}]`
}
}
var isString = isType("String");
var a = "nihao";
console.log(isString(a));