Tips : Call 和 apply 非常类似 以Call方法为例.
调用一个对象的一个方法,以另一个对象替换当前对象。
Call 方法可以用来代替另一个对象调用一个方法。
Call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
JavaScript 代码 :
var Animal = cc.Sprite.extend({
name : null,
ctor: function(){
this._super();
this.name = "Animal";
},
showName: function(){
cc.log(this.name);
},
})
var Cat = cc.Sprite.extend({
name : null,
ctor: function(){
this._super();
this.name = "Cat";
},
})
var cat = new Cat();
var animal = new Animal();
animal.showName() //结果为Animal
cat.showName(); //报错
animal.showName.call(cat); //结果为Cat
//通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。
//animal.showName.apply(cat,[]);
call 的意思是把 animal 的方法放到cat上执行,原来cat是没有showName() 方法,现在是把animal 的showName()方法放到 cat上来执行,所以this.name 应该是 Cat
JavaScript 代码 :
function add(a,b)
{
alert(a+b);
}
function sub(a,b)
{
alert(a-b);
}
add.call(sub,3,1);
这个例子中的意思就是用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4);
注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。
定义一个log方法 :
function log(msg){
console.log(msg);
}
log(1) // 1
log(1, 2) // 1
可以看出来 这个方法只能接受一个参数, 虽然可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 替代 call .
这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:
function log(){
console.log.apply(console, arguments);
}
再次尝试 :
log(1) // 1
log(1, 2) // 1 2
结果就正确了!
其实, 在 cocos2d - js 里 cc.log 的实现方式正是如此 !
bind方法本身和 apply 、call很类似, 也同样是改变this指向的方法, 但是bind使用的地方与apply 和 call 有些不同.
bind方法会创建一个新函数, 称作绑定函数, 当调用bind函数时, 为以第一个参数为this(通常传入的也是this), 传入bind的第二个以及以后的参数加上绑定函数运行时本身的参数, 按照顺序作为原函数的参数来调用函数.
在具体实例中, 我们通常用self、that等, 用来保存this, 例如 :
var foo = {
num: 1,
eventBind: function(){
var self = this;
$('.someClass').on('click',function(event) {
console.log(self.num); //1
});
}
}
————————-下文为网络原文————————-
由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $(‘.someClass’).on(‘click’,function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:
var foo = {
bar : 1,
eventBind: function(){
$('.someClass').on('click',function(event) {
console.log(this.bar); //1
}.bind(this));
}
}
在上述代码里,bind() 创建了一个函数,当这个click事件绑定在被调用的时候,它的 this 被传入(调用bind()时传入的参数)。因此,这里我们传入想要的上下文 this( foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向 foo 对象。
例如:
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
bar(); // undefined
var func = bar.bind(foo);
func(); // 3
这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。
有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
var sed = {
x:4
}
var func = bar.bind(foo).bind(sed);
func(); //?
var fiv = {
x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?
答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。
那么 apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个栗子:
var A = {
name : "A",
}
var B = {
name : "B",
getName : function(){
console.log(this.name);
},
}
B.getName.bind(A)(); //A
B.getName.call(A); //A
B.getName.apply(A); //A
三个输出的都是A,但是注意看使用 bind() 方法的,他后面多了对括号。
也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。