假设页面有个按钮btn,实现点击打印message信息和事件类型(暂只介绍ES5,js新的提案
中提出了“函数绑定”(function bind)运算符::
)。
第一步:
var handler = {
message:'hello world',
handleClick:function(e){
console.log(this.message)
console.log(e.type)
}
}
btn.addEventListener('click', handler.handleClick ,false);
预期中,结果打印hello world、click
,结果却是:undefined、click
.
根据闭包 的特性,上面代码中handler.handleClick()的上下文环境没有得到保留,所以在函数内部this的指向不是handler而是btn对象,所以不存在message属性。
第二步:
我们可以使用一个闭包去修复上面this指向问题。
var handler = {
message:'hello world',
handleClick:function(e){
console.log(this.message)
console.log(e.type)
}
}
btn.addEventListener('click', function(e){
handler.handleClick(e);
} ,false)
结果打印hello world、click
,没有问题。
第三步:
我们可以构建一个通用的函数bind(),用于将函数绑定到指定上下文环境。
function bind(fn,context){
return function(){
fn.apply(context, arguments)
}
}
btn.addEventListener('click', bind(handler.handleClick,handler) ,false)
结果打印hello world、click
,没有问题。
bind()中使用了apply改变了fn的上下文环境。arguments是内部匿名函数的,而非bind的。所以可以拿到对应的event参数。
bind的简单使用:
Function.prototype.bind():bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
btn.addEventListener('click', handler.handleClick.bind(handler) ,false)
结果打印hello world、click
,没有问题。
关于bind的Polyfill,MDN介绍的很详细,用于兼容部分浏览器。
第四步:
使用函数柯里化,加入额外参数。
var handler = {
message:'hello world',
handleClick:function(params, e){
console.log(this.message)
console.log(e.type)
console.log(params)
}
}
function bind(fn,context){
var fnArgs = Array.prototype.slice.call(arguments, 2);
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = fnArgs.concat(innerArgs);
fn.apply(context, finalArgs)
}
}
btn.addEventListener('click', bind(handler.handleClick,handler,'first args') ,false)
结果打印hello world , click , first args
。
ES5的 bind() 方法也实现函数柯里化,只要在 this 的值之后再传入额外参数
var handler = {
message:'hello world',
handleClick:function(params1, params2, e){
console.log(this.message)
console.log(e.type)
console.log(params1)
console.log(params2)
}
}
btn.addEventListener('click', handler.handleClick.bind(handler, 'first args', 'second args') ,false)
结果打印hello world , click , first args, second args
。