<body>
<h3>设计模式知识连载(43)---参与者模式:</h3>
<p>
在特定的作用域中执行给定的函数,并将参数原封不动的传递。
</p>
<hr>
<button>点击</button>
<p>hello</p>
<script type="text/javascript">
/**
* 案例一:传递数据,方式一:初始
*/
// // 单体模式定义命名空间
// var A = {} ;
// // 事件绑定方法
// A.event.on = function(dom, type, fn) {
// // w3c标准事件绑定
// if(dom.addEventListener) {
// dom.addEventListener(type, fn, false) ;
// // IE事件绑定
// }else if(dom.attachEvent) {
// dom.attachEvent('on' + type, fn) ;
// // DOM0级事件绑定
// }else {
// dom['on' + type] = fn ;
// }
// }
/**
* 案例一:传递数据,方式二:进阶
*/
// // 单体模式定义命名空间
// var A = {} ;
// // 事件绑定方法
// A.event.on = function(dom, type, fn, data) {
// // w3c标准事件绑定
// if(dom.addEventListener) {
// dom.addEventListener(type, function(e) {
// *
// * 在dom环境中调用fn,并传入事件对象与data数据参数
// *
// * 知识点:JavaScript中的call和apply方法可以使我们在特定作用域中执行某个函数,并传入参数。所以,在该回调函数中,我们这可以借助call函数实现。
// fn.call(dom, e, data) ;
// }, false) ;
// }else if(dom.attachEvent) {
// dom.attachEvent('on' + type, function(e) {
// fn.call(dom, e, data) ;
// }) ;
// }else {
// dom['on' + type] = function(e) {
// fn.call(dom, e, data) ;
// }
// }
// }
/**
* 案例二:函数绑定,方式一:
*/
// // 函数绑定bind
// function bind(fn, context) {
// // 闭包返回新函数
// return function() {
// // 对fn装饰并返回
// return fn.apply(context, arguments) ;
// }
// }
// // 测试用例:
// var demoObj = {
// title : '这是一个例子'
// } ;
// function demoFn() {
// console.log(this.title) ;
// } ;
// // 让demoObj参与demoFn的执行
// var bindFn = bind(demoFn, demoObj) ;
// demoFn() ; // undefined
// bindFn() ; // 这是一个例子
/**
* 案例二:函数绑定,方式二:
*/
// // 函数绑定bind
// function bind(fn, context) {
// // 闭包返回新函数
// return function() {
// // 对fn装饰并返回
// return fn.apply(context, arguments) ;
// }
// }
// var btn = document.getElementsByTagName('button')[0] ;
// var p = document.getElementsByTagName('p')[1] ;
// // 对demoFn改进,在控制台输出参数与this对象
// function demoFn() {
// console.log(arguments) ;
// console.log('-----------------------') ;
// console.log(this) ;
// }
// // 未设置提供参与对象
// var bindFn = bind(demoFn) ;
// // 绑定事件
// btn.addEventListener('click', bindFn) ;
// var bindFn = bind(demoFn, btn) ;
// // 提供btn元素参与对象
// btn.addEventListener('click', bindFn) ;
// var bindFn = bind(demoFn, p) ;
// // 提供p元素参与对象
// btn.addEventListener('click', bindFn) ;
// // 移除事件【移除最近的那个】
// btn.removeEventListener('click', bindFn) ;
/**
* 案例三:函数柯里化,方式一:
*/
// 函数柯里化
function curry(fn) {
// 缓存数组slice方法Array.prototype.slice
var _slice = [].slice ;
// 从第二个参数开始截取参数
var args = _slice.call(arguments, 1) ;
// 闭包返回新函数
return function() {
// 将参数(类数组)转化为数组
var addArgs = _slice.call(arguments) ;
// 拼接参数
var allArgs = args.concat(addArgs) ;
// 返回新函数
return fn.apply(null, allArgs) ;
}
}
// 测试用例
// 正常加法器
function add(num1, num2) {
return num1 + num2 ;
}
// 加5加法器
function add5(num) {
return add(5, num) ;
}
// 测试加法器
console.log('1 + 2 = ', add(1, 2)) ;
// 测试加5加法器
console.log('5 + 6 = ', add5(6)) ;
// 函数柯里化创建加5加法器
var curry_add5 = curry(add, 5) ;
console.log('5 + 7 = ', curry_add5(7)) ;
var curry_add7_8 = curry(add, 7, 8) ;
console.log('7 + 8 = ', curry_add7_8()) ;
/**
* 案例三:反柯里化,方式一:
*/
// 反柯里化
Function.prototype.uncurry = function() {
// 保存当前对象
var that = this;
return function() {
return Function.prototype.call.apply(that, arguments) ;
}
}
// 测试用例
// 用Object.prototype.toString校验对象类型时:
// 获得校验方法
var toString = Object.prototype.toString.uncurry() ;
// 测试对象数据类型
console.log('toString(function(){}):', toString(function(){})) ;
console.log('toString([]):', toString([])) ;
// 用数组的push方法为对象添加数据成员:
// 保存数组push方法
var push = [].push.uncurry() ;
// 创建一个对象
var demoArr = {} ;
// 通过push方法为对象添加数据成员
push(demoArr, '第一个成员', '第二个成员') ;
console.log(demoArr) ;
/**
* 案例四:重构bind,方式一:
*/
// 重写bind
function bind(fn, context) {
// 缓存数组的slice方法
var _slice = Array.prototype.slice;
// 从第三个参数开始截取参数(包含第三个参数)
var args = _slice.call(arguments, 2) ;
// 返回新方法
return function() {
// 将参数转化为数组
var addArgs = _slice.call(arguments) ;
// 拼接参数
var allArgs = addArgs.concat(args) ;
// 对fn装饰并返回
return fn.apply(context, allArgs) ;
}
}
// 测试用例
var btn = document.getElementsByTagName('button')[0] ;
var p = document.getElementsByTagName('p')[1] ;
var demoData1 = {
text : '这是第一组数据'
};
var demoData2 = {
text : '这是第二组数据'
}
function demoFn() {
console.log('arguments:', arguments) ;
console.log('----------------------') ;
console.log('this:', this) ;
}
// 提供btn元素、demoData1参与对象
// var btnFn = bind(demoFn, btn, demoData1) ;
// btn.addEventListener('click', btnFn) ;
// 提供btn元素、demoData1、demoData2参与对象
// var btnFn2 = bind(demoFn, btn, demoData1, demoData2) ;
// btn.addEventListener('click', btnFn2) ;
// 提供p元素、demoData1参与对象
// var btnFn3 = bind(demoFn, p, demoData1) ;
// btn.addEventListener('click', btnFn3) ;
/* 看看浏览器内置的bind方法 */
var bindFn_browser = bind(p, demoData1) ;
btn.addEventListener('click', bindFn_browser) ;
/**
* 案例五:兼容各个浏览器,方式一:
*/
// 兼容各个浏览器
if(Function.prototype.bind === undefined) {
Function.prototype.bind = function(context) {
// 缓存数组slice方法
var _slice = Array.prototype.slice;
// 从第二个参数截取参数
var args = _slice.call(arguments, 1) ;
// 保存当前函数引用
var that = this ;
// 返回新的函数
return function() {
// 将参数数组化
var addArgs = _slice.call(arguments) ;
// 拼接参数,注意:传入的参数放在了后面
var allArgs = args.concat(addArgs) ;
// 对当前函数装饰并返回
return that.apply(context, allArgs) ;
}
}
}
</script>
</body>