this.num = 9;
var mymodule = { num: 81, getNum: function() { return this.num; } }; module.getNum(); // 81 var getNum = module.getNum;
getNum(); // 9, 因为在这个例子中,"this"指向全局对象 // 创建一个'this'绑定到module的函数 var boundGetNum = getNum.bind(module);
boundGetNum(); // 81
if(!Function.prototype.bind){ Function.prototype.bind = function(oThis){ if(typeof this !=="function"){ //如果不函数抛出异常 throw new TyperError("") } var aArgs = Array.prototype.slice.call(arguments,1), //此处的aArgs是除函数外的参数 fToBind = this, //要绑定的对象 fNOP = function(){}, fBound = function(){ return fToBind.apply( //没看清楚为什么要 this. instanceof fNOP ? this: oThis, 应该直接OThis吧 this instanceof fNOP ? this:oThis||this, aArgs.concat(Array.prototype.slice.call(arguments)) 参数合并 ); ) }; fNOP.prototype = this.prototype; // 利用中间函数 fNOP 来借用 被执行函数ABC的原型 fBound.prototype = new fNOP(); // 因为 new FNOP ( ) 这个实例有个属性 __proto__ 指向了 fNOP的原型, 这样改变fBound的原型不会影响到 被执行函数ABC的原型 return fBound; } }
明白 bind
的用法就必须要知道 apply
的用法,MDN 指出,apply
是直接修改了函数内部的指向到第一个参数,并将第二个参数数组传参进函数并运行这个函数。也就是说
var obj = {test: function() { console.log(this, arguments) }},
func = obj.test;
obj.test("Hello", ",", "world", "!");
func.apply(obj, ["Hello", ",", "world", "!"]);
这两种运行方式是一样的。那么回到 Polyfill 中发现参数的写法是 args.concat(slice.call(arguments))
。args
是将 bind
时候定义的除第一个参数外的其它参数,而此时的 arguments
是指函数调用时候的参数,通过数组的操作将这两个参数合并成一个数组传入函数内部。看个例子你可能更容易明白:
/** 代码接上 **/
var newFunc = func.bind(obj, "Hello", ",");
newFunc("world", "!");
那么再来回答问题一,这个是典型的属性继承的方法,本来使用
bound.prototype = self.prototype
就可以将原属性集成过来了,但是这样两个对象属性都指向同一个地方,修改 bound.prototype
将会造成 self.prototype
也发生改变,这样并不是我们的本意。所以通过一个空函数 nop
做中转,能有效的防止这种情况的发生。
bind返回的是函数
if (!Function.prototype.bind) {
Function.prototype.bind = function(obj) {
var _self = this
,args = arguments;
return function() {
_self.apply(obj, Array.prototype.slice.call(args, 1));
}
}
}