19.二次封装函数1
20.二次封装函数2
21.使用 arguments
22.柯里化
23.且运算
24.二进制转换
19.二次封装函数1
要求:
已知函数 fn 执行需要 3 个参数。请实现函数 partial,调用之后满足如下条件:
1、返回一个函数 result,该函数接受一个参数
2、执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致
输入例子:
var sayIt = function(greeting, name, punctuation) { return greeting + ‘, ’ + name + (punctuation || ‘!’); }; partial(sayIt, ‘Hello’, ‘Ellie’)(‘!!!’);
输出例子:
Hello, Ellie!!!
/ 一般写法
function partial(fn, str1, str2) {
function result(str3) {
return fn(str1, str2, str3);
}
return result;
}
// call
function partial(fn, str1, str2) {
function result(str3) {
return fn.call(this, str1, str2, str3);
}
return result;
}
// apply(这里只是为了对照)
function partial(fn, str1, str2) {
function result(str3) {
return fn.apply(this, [str1, str2, str3]);
}
return result;
}
// 这个bind会生成一个新函数对象, 它的str1, str2参数都定死了, str3未传入, 一旦传入就会执行
function partial(fn, str1, str2) {
return fn.bind(this, str1, str2); // 或 return fn.bind(null, str1, str2);
}
// bind同上, 多了一步, 把str3传入的过程写在另一个函数里面, 而另一个函数也有str1, str2参数
function partial(fn, str1, str2) {
function result(str3) {
return fn.bind(this, str1, str2)(str3);
}
return result;
}
// 匿名函数
function partial(fn, str1, str2) {
return function(str3) {
return fn(str1, str2, str3);
}
}
// ES6
const partial = (fn, str1, str2) => str3 => fn(str1, str2, str3);
20.二次封装函数2
要求:
实现函数 partialUsingArguments,调用之后满足如下条件:
1、返回一个函数 result
2、调用 result 之后,返回的结果与调用函数 fn 的结果一致
3、fn 的调用参数为 partialUsingArguments 的第一个参数之后的全部参数以及 result 的调用参数
思路:
arguments不能用slice方法直接截取,需要先转换为数组,var args = Array.prototype.slice.call(arguments);
合并参数可以使用concat方法,并且也需要将arguments先转换为数组才能使用concat进行合并。最用使用apply执行传入的函数即可。
function partialUsingArguments(fn) {
//先获取p函数第一个参数之后的全部参数
var args = Array.prototype.slice.call(arguments,1);
//声明result函数
var result = function(){
//使用concat合并两个或多个数组中的元素
return fn.apply(null, args.concat([].slice.call(arguments)));
}
return result;
}
21.使用 arguments
要求:
函数 useArguments 可以接收 1 个及以上的参数。请实现函数 useArguments,返回所有调用参数相加后的结果。本题的测试参数全部为 Number 类型,不需考虑参数转换。
思路:
本题考查的是对于arguments的使用,arguments能获得函数对象传入的参数组,类似与一个数组,能够通过length获取参数个数,能通过下标获取该位置的参数,但是它不能使用forEach等方法。本题先通过arguments.length获得参数个数,然后循环求和,得出结果。
输入例子:
useArguments(1, 2, 3, 4)
输出例子:
10
// 一般写法,直接利用arguments只有length属性的特点
function useArguments() {
/*
因为参数数量不定,可以先获取参数个数arguments.length
然后循环求值
*/
//声明一个变量保存最终结果
var sum = 0;
//循环求值
for(var i = 0; i < arguments.length; i++){
sum += arguments[i];
}
return sum;
}
// call
function useArguments() {
var arr = [].slice.call(arguments); // 转成数组 ([]为Array.prototype的语法糖)
return arr.reduce(function(a, b) {
return a + b;
});
}
/* call, bind, apply会改变生成函数对象的this, 使得arguments可以直接使用数组的方法,
所以也可不转换成数组而直接使用reduce */
// call同上, 精简版
function useArguments() {
return [].reduce.call(arguments, function(a, b) {
return a + b;
});
}
// bind
function useArguments() {
return [].reduce.bind(arguments, function(a, b) {
return a + b;
})();
}
// apply
function useArguments() {
return [].reduce.apply(arguments, [function(a, b) {
return a + b;
}]);
}
// eval的妙用,但不推荐使用eval
function useArguments() {
var arr = Array.prototype.slice.call(arguments);
return eval(arr.join('+'));
}
22.柯里化
题目描述
已知 fn 为一个预定义函数,实现函数 curryIt,调用之后满足如下条件:
1、返回一个函数 a,a 的 length 属性值为 1(即显式声明 a 接收一个参数)
2、调用 a 之后,返回一个函数 b, b 的 length 属性值为 1
3、调用 b 之后,返回一个函数 c, c 的 length 属性值为 1
4、调用 c 之后,返回的结果与调用 fn 的返回值一致
5、fn 的参数依次为函数 a, b, c 的调用参数
输入例子:
var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);
输出例子:
6
//不用 arguments.callee 的方法,用变量名代替了,大同小异:
function curryIt(fn) {
var length = fn.length,//等于fn传入参数个数
args = [];
var result = function (arg){
args.push(arg);
length --;
if(length <= 0 ){
return fn.apply(this, args);
} else {
return result;
}
}
return result;
}
// apply
function curryIt(fn) {
var arr = [];
return function(a) {
arr.push(a);
return function(b) {
arr.push(b);
return function(c) {
arr.push(c);
return fn.apply(this, arr);
}
}
}
}
// 推荐写法
function curryIt(fn) {
return function(e1) {
return function(e2) {
return function(e3) {
return fn(e1, e2, e3); // return fn.call(this, e1, e2, e3); 与之等价
}
}
}
}
// 箭头函数
const curryIt = fn => e1 => e2 => e3 => fn(e1, e2, e3);
关于科里化更深入的理解,详见:JS中的柯里化(currying)
http://www.zhangxinxu.com/wordpress/2013/02/js-currying/
23.且运算
要求:
返回参数 a 和 b 的逻辑且运算结果。
思路:
且运算符”&&”的运算规则是:如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。
例如 2&&'d' ->"d"
2&&0 -> 0
function and(a, b) {
return !!(a && b)
//如果a为true,b为非Boolean就会返回非Boolean值,所以加一步转换
}
//and(3,2) true
//and(0,3) false
//and(2,0) false
!!一般用来将后面的表达式强制转换为布尔类型的数据(boolean),也就是只能是true或者false;
var a;
var b=!!a;
a默认是undefined。!a是true,!!a则是false
24.二进制转换
要求:
给定二进制字符串,将其换算成对应的十进制数字
思路:
parseInt方法可以将其它进制转换为十进制,只需要给该方法传入需要转换的字符串和该字符串的进制表示两个参数即可。
function base10(str) {
/**
其它进制转十进制
parseInt(str,2)
parseInt(str,8)
parseInt(str,16)
*/
return parseInt(str,2);
}