参与者(participator)
在特定的作用域中执行给定的函数,并将参数原封不动地传递
需求:实现系统的bind功能
传递参数
存在的
缺点
:添加的事件回调函数不能移除(removeEventListener)
function $(id) {
return document.getElementById(id);
}
const A = {
on(dom, type, fn, ...args) {
dom.addEventListener(type, function (e) {
fn && fn(dom, e, args);
}, false);
}
};
A.on($('btn1'), 'click', function (dom, e, args) {
console.log(dom, e, args); // DOM PointerEvent{} [{ name: 'Lee' }, { age: 18 }]
}, {
name: 'Lee' }, {
age: 18 });
函数绑定
实现建简易的
bind
功能
function bind(context, fn) {
return function (...args) {
return fn.apply(context, args);
}
}
let bindFn = bind({
name: 'Lee', age: 18 }, function (msg) {
console.log(`${msg} ${this.name}`);
});
bindFn('Hello'); // Hello Lee
将bind
应用于事件
这种方式传参还是存在一定的局限性,我们必须事先明确参数是什么然后在传递下去(
通过柯里化解决此问题
)
function $(id) {
return document.getElementById(id);
}
function bind(context, fn) {
return function (...args) {
return fn.apply(context, args);
}
}
const bindFn = bind({
dom: $('btn1'), args: {
name: 'Lee' } }, function (e) {
console.log(this, e); // {dom: button#btn1, args: { name: 'Lee' }} PointerEvent{}
this.dom.removeEventListener('click', bindFn);
});
$('btn1').addEventListener('click', bindFn, false);
原生bind
function sayHi(name) {
console.log(`${this.msg} ${name}`);
}
let bindFn = sayHi.bind({
msg: 'Hello' }, 'Lee');
bindFn(); // Hello Lee
函数柯里化
函数柯里化的思想是
对函数的参数分割
,类似面向语言中的类的多态,根据传递的参数不同,可以让一个函数存在多种状态实现函数的柯里化是以函数为基础的,借助柯里化器伪造其他函数,让这些伪造的函数在执行时调用这个基函数完成不同的功能
通过函数柯里化器对add方法实现的多态拓展且不需要像以前那样明确声明函数了,因为函数的创建过程已经在函数柯里化器中完成了
// 创建柯里化器
function curry(fn, ...args1) {
return function (...args2) {
// 所有参数
let args = [...args1, ...args2];
return fn.apply(null, args);
}
}
curry((...args) => {
console.log(args); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
}, 1, 2, 3, 4, 5, 6)(7, 8, 9);
// 加法器
function add(a, b) {
return a + b;
}
let sum1 = curry(add, 1)(2);
console.log(sum1); // 3
let sum2 = curry(add, 1, 2)();
console.log(sum2); // 3
利用柯里化重构bind
优化传参
function $(id) {
return document.getElementById(id);
}
function bind(context, fn, ...args1) {
return function (...args2) {
// 所有参数
let args = [...args1, ...args2];
return fn.apply(context, args);
}
}
const bindFn1 = bind(null, (...args) => {
console.log(args); // [1, 2, 3, 4, 5, 6, 7, 8]
}, 1, 2, 3, 4, 5)
bindFn1(6, 7, 8);
const bindFn2 = bind($('btn1'), function (a, b, ...args) {
console.log(this, a, b, args); // DOM [1, 2, 3, 4, 5, 6, PointerEvent]
this.removeEventListener('click', bindFn2);
}, 1, 2, 3, 4, 5, 6);
$('btn1').addEventListener('click', bindFn2, false);
兼容bind
方法
// 兼容各个浏览器
if (Function.prototype.bind === undefined) {
Function.prototype.bind = function (context, ...args1) {
const that = this;
return function (...args2) {
// 所有参数
let args = [...args1, ...args2];
return that.apply(context, args);
}
}
}
const logNum = function (...args) {
console.log(args); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
};
logNum.bind(null, 1, 2, 3, 4, 5)(6, 7, 8, 9);
特点
参与者模式实质
上是两种技术
的结晶函数绑定
函数柯里化
反柯里化
方便对方法的调用
// 反柯里化
Function.prototype.uncurry = function () {
var that = this;
return function (...args) {
return Function.prototype.call.apply(that, args);
}
};
// 以前的方法
{
Object.prototype.toString.call(function () {
}); // '[object Function]'
Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call(123); // '[object Number]'
}
// 反柯里化后的方法
{
const toString = Object.prototype.toString.uncurry();
toString(function () {
}); // '[object Function]'
toString([]); // '[object Array]'
toString(123); // '[object Number]'
}
var push = [].push.uncurry(); // 保存数组push方法
var obj = {
};
push(obj, 'Lee', 18); // 通过push方法为对象添加数据成员
console.log(obj); // {0: 'Lee', 1: 18, length: 2}