偏函数
概念
固定一个函数的一些参数,然后产生另一个更小元的函数
元
函数参数的个数
应用
function partial(fn) {
var args = [].slice.call(arguments, 1);
return function () {
var newArgs = args.concat([].slice.call(arguments));
return fn.apply(this, newArgs);
};
}
function add(a, b) {
return a + b;
}
var addOne = partial(add,1)
console.log(addOne(2));
// lodash.partial 占位符
var _ = {};
function partial(fn) {
var args = [].slice.call(arguments, 1);
return function () {
var position = 0,
len = args.length;
for (var i = 0; i < len; i++) {
// 判断是否是占位符,如果是取参数的下一个赋值
args[i] = args[i] === _ ? arguments[position++] : args[i];
}
while (position < arguments.length) args.push(arguments[position++]);
return fn.apply(this, args);
};
}
柯里化
将多参数函数转换成多个单参数函数
延迟计算
function currying(func) {
const args = [];
return function result(...rest) {
if (rest.length === 0) {
return func(...args);
} else {
args.push(...rest);
return result;
}
}
}
const add = (...args) => args.reduce((a, b) => a + b);
const sum = currying(add);
sum(1,2)(3); // 未真正求值
sum();
let obj = {
name: "a",
};
const fun = function () {
console.log(this.name);
}.bind(obj);
fun();
动态创建函数
const addEvent = (function () {
if (window.addEventListener) {
return function (type, el, fn, capture) {
el.addEventListener(type, fn, capture);
};
} else if (window.attachEvent) {
return function (type, el, fn) {
el.attachEvent("on" + type, fn);
};
}
})();
// 惰性函数
function addEvent(type, el, fn, capture = false) {
// 重写函数
if (window.addEventListener) {
addEvent = function (type, el, fn, capture) {
el.addEventListener(type, fn, capture);
};
} else if (window.attachEvent) {
addEvent = function (type, el, fn) {
el.attachEvent("on" + type, fn);
};
}
// 执行函数,有循环爆栈风险
addEvent(type, el, fn, capture);
}
参数复用
const toStr = Function.prototype.call.bind(Object.prototype.toString);
// 改造前
[1, 2, 3].toString(); // "1,2,3"
'123'.toString(); // "123"
123.toString(); // SyntaxError: Invalid or unexpected token
Object(123).toString(); // "123"
// 改造后
toStr([1, 2, 3]); // "[object Array]"
toStr('123'); // "[object String]"
toStr(123); // "[object Number]"
toStr(Object(123)); // "[object Number]"
反柯里
概念
扩大使用范围,创建一个应用范围更广的函数,使本来只有特定对象才适用的方法,扩展到更多的对象。
应用
Function.prototype.unCurrying = function () {
// this 是传递过来的函数
var self = this;
return function () {
// arguments 是调用 unCurrying 函数以后传递的参数
// 第一个参数是 call 函数的 this
return Function.prototype.call.apply(self, arguments);
};
};
function unCurrying(fn) {
return function () {
var args = [].slice.call(arguments);
var that = args.shift();
return fn.apply(that, args);
};
}
// 轻提示
function Toast(option) {
this.prompt = "";
}
Toast.prototype.show = function (a) {
console.log(this.prompt);
};
// 新对象
var obj = {
prompt: "新对象",
};
// 使用
var objShow = Toast.prototype.show.unCurrying();
// var objShow = unCurrying(Toast.prototype.show);
objShow(obj);
借用原生方法
- 对象借用数组方法
Function.prototype.unCurrying = function () {
var self = this;
return function () {
return Function.prototype.call.apply(self, arguments);
};
};
var obj = {};
var push = Array.prototype.push.unCurrying();
push(obj, "a");
console.log(Array.from(obj));
arguments转数组
var slice = Array.prototype.slice.unCurrying()
~function a() {
console.log(slice(arguments,0));
}(1,2,3)
getElementById
var call = Function.prototype.call.unCurrying();
var fn = function (id) {
console.log(this.getElementById(id));
};
call(fn, document, "a");
- 批量增强对象
var add_fn = function (obj, fn_keys) {
for (var i = 0, ary = fn_keys.split(","), fn; (fn = ary[i++]); ) {
~(function (fn) {
var new_fn = Array.prototype[fn].unCurrying();
obj[fn] = function () {
console.log([this].concat(Array.prototype.slice.call(arguments)));
new_fn.apply(
this,
[this].concat(Array.prototype.slice.call(arguments))
);
return this;
};
})(fn);
}
};
var A = function () {};
add_fn(A.prototype, "push,indexOf,shift,pop,forEach");
var a = new A();
a.push(1)
.push(2)
.push(3)
.forEach(function (n) {
console.log(n);
});
console.log(a);