【前端100问】Q84:请实现一个 add 函数,满足以下功能。
写在前面
此系列来源于开源项目:前端 100 问:能搞懂 80%的请把简历给我
为了备战 2021 春招
每天一题,督促自己
从多方面多角度总结答案,丰富知识
请实现一个 add 函数,满足以下功能。
简书整合地址:前端 100 问
正文回答
题目
add(1); // 1
add(1)(2); // 3
add(1)(2)(3);// 6
add(1)(2, 3); // 6
add(1, 2)(3); // 6
add(1, 2, 3); // 6
回答
function add() {
let args = [].slice.call(arguments);
let fn = function () {
let fn_args = [].slice.call(arguments);
return add.apply(null, args.concat(fn_args));
};
fn.toString = function () {
return args.reduce((a, b) => a + b);
};
return fn;
}
扩展
高阶函数
高阶函数英文叫 Higher-order function,它的定义很简单,就是至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入
- 输出一个函数
也就是说高阶函数是对其他函数进行操作的函数,可以将它们作为参数传递,或者是返回它们。 简单来说,高阶函数是一个接收函数作为参数传递或者将函数作为返回值输出的函数。
函数作为参数传递
JavaScript 语言中内置了一些高阶函数,比如 Array.prototype.map
,Array.prototype.filter
和 Array.prototype.reduce
,它们接受一个函数作为参数,并应用这个函数到列表的每一个元素。我们来看看使用它们与不使用高阶函数的方案对比。
Array.prototype.map
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果,原始数组不会改变。传递给 map 的回调函数(callback)接受三个参数,分别是 currentValue、index(可选)、array(可选),除了 callback 之外还可以接受 this 值(可选),用于执行 callback 函数时使用的 this 值。
来个简单的例子方便理解,现在有一个数组 [1, 2, 3, 4],我们想要生成一个新数组,其每个元素皆是之前数组的两倍,那么我们有下面两种使用高阶和不使用高阶函数的方式来实现。
// 不使用高阶函数
// 木易杨
const arr1 = [1, 2, 3, 4];
const arr2 = [];
for (let i = 0; i < arr1.length; i++) {
arr2.push(arr1[i] * 2);
}
console.log(arr2);
// [2, 4, 6, 8]
console.log(arr1);
// [1, 2, 3, 4]
// 使用高阶函数
// 木易杨
const arr1 = [1, 2, 3, 4];
const arr2 = arr1.map((item) => item * 2);
console.log(arr2);
// [2, 4, 6, 8]
console.log(arr1);
// [1, 2, 3, 4]
Array.prototype.filter
略
Array.prototype.reduce
略
函数作为返回值输出
isType 函数
我们知道在判断类型的时候可以通过 Object.prototype.toString.call
来获取对应对象返回的字符串,比如:
let isString = (obj) =>
Object.prototype.toString.call(obj) === "[object String]";
let isArray = (obj) => Object.prototype.toString.call(obj) === "[object Array]";
let isNumber = (obj) =>
Object.prototype.toString.call(obj) === "[object Number]";
可以发现上面三行代码有很多重复代码,只需要把具体的类型抽离出来就可以封装成一个判断类型的方法了,代码如下。
let isType = (type) => (obj) => {
return Object.prototype.toString.call(obj) === "[object " + type + "]";
};
isType("String")("123"); // true
isType("Array")([1, 2, 3]); // true
isType("Number")(123); // true
这里就是一个高阶函数,因为 isType 函数将 obj => { ... } 这一函数作为返回值输出。
回到题目本身
我们知道打印函数时会自动调用 toString()
方法,函数 add(a) 返回一个闭包 sum(b),函数 sum() 中累加计算 a = a + b,只需要重写 sum.toString()方法返回变量 a 就可以了。
function add(a) {
function sum(b) { // 使用闭包
a = a + b; // 累加
return sum;
}
sum.toString = function() { // 重写toString()方法
return a;
}
return sum; // 返回一个函数
}
add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10