《Javascript高级程序设计》读书笔记之bind函数详解 – GongQi

为什么需要bind

var name = The Window;
var object = {
name:
My Object,
getNameFunc: function () {
return function () {
return this.name;
}
}
};

alert(object.getNameFunc()()); //“The Window”

object.getNameFunc()返回一个匿名函数,在全局环境调用该函数,this指向的全局对象

解决这一问题,可以像下面这样,将匿名函数外部作用域中this对象保存在闭包能够访问到的变量中

var name = The Window;
var object = {
name:
My Object,
getNameFunc: function () {
var that = this;
return function () {
return that.name;
}
}
};

alert(object.getNameFunc()()); //“My Object”

上述解决方法需要修改对象的方法,如果不能修改原对象的方法,该如何做呢?

这时,我们可以像下面这样,使用apply或call方法指定函数的作用域

var name = The Window;
var object = {
name:
My Object,
getNameFunc: function () {
return function () {
return this.name;
}
}
};
var func=object.getNameFunc();
alert(func.apply(
object)); //“My Object”

通过apply、call,已经可以输出预期的My Object

但是,每次调用时都需要以func.apply(object)的形式调用,这不是很怪么

理想的调用方式,当然是在通过某种处理后,之后可以以func()形式调用,像下面这样

var name = The Window;
var object = {
name:
My Object,
getNameFunc: function () {
return function () {
return this.name;
}
}
};
var func=object.getNameFunc();
func
=func.bind(object);
alert(func());
//“My Object”

ECMAScript 5中的bind

 ECMAScript 5定了了bind方法,这个方法会创建一个函数实例,其this值会被绑定到传给bind函数的值,上面代码给出了bind函数的使用方式,再给一个简单示例。

window.color=red;
var o={color:blue};
function sayColor(){
alert(
this.color);
}

var func=sayColor.bind(o);
func();
//“blue”

虽然大部分浏览器中已经可以使用ECMAScript 5定义的这个方法,但在少数不支持的浏览器中你还是会遇到兼容性问题,这是如何处理呢?

通过上面apply、call方法使用示例 ,可以像下面这样提供一个解决方案

Function.prototype.bind=Function.prototype.bind||
function(context){
var self=this;
return function()
{
return self.apply(context,arguments);
}
}

Prototype.js中的bind

// The .bind method from Prototype.js
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};

 上述代码中,

args=Array.prototype.slice.call(arguments)将调用bind函数时参数集合arguments转换为数组array

object=args.shift()将args数组第一个元素取出作为当前对象

匿名函数中,调用args.concat(Array.prototype.slice.call(arguments))是为了将调用匿名函数时传入的参数与调用bind时参数合并成一个参数数组

以一个调用示例来看上述过程

var obj = { x: prop x };
//args = Array.prototype.slice.call(arguments)后args = [obj, 12, 23 ]
//object=args.shift()后,args =[12, 23] ,object =obj

var boundExample = example.bind(obj, 12, 23); boundExample(36, 49); // arguments => 36, 49 ,调用args.concat(Array.prototype.slice.call(arguments))后,arguments that our example() function receives => [12, 23, 36, 49]

Firefox中的bind

if (!Function.prototype.bind) {
Function.prototype.bind
= function (oThis) {
if (typeof this !== function) {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError(Function.prototype.bind – what is trying to be bound is not callable);
}

var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind
= this,
fNOP
= function () {},
fBound
= function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis
|| window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};

fNOP.prototype = this.prototype;
fBound.prototype
= new fNOP();

return fBound;
};
}

Firefox为bind提供了一个兼容实现,主要代码与prototype.js中实现类似,不再逐句解释了

 

本文链接:《Javascript高级程序设计》读书笔记之bind函数详解,转载请注明。



You must enable javascript to see captcha here!

Copyright © All Rights Reserved · Green Hope Theme by Sivan & schiy · Proudly powered by WordPress

无觅相关文章插件,快速提升流量