在JavaScript中,call、apply和bind是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向。
call、apply、bind方法的共同点和区别:
- apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
- apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文(函数的每次调用都会拥有一个特殊值——本次调用的上下文(context)——这就是this关键字的值。);
- apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
1. call
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明: call 方法可以用来代替另一个对象调用一个方法。
call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
thisObj的取值有以下4种情况:
(1) 不传,或者传null,undefined, 函数中的this指向window对象
(2) 传递另一个函数的函数名,函数中的this指向这个函数的引用
(3) 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean
(4) 传递一个对象,函数中的this指向这个对象
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name); //cheese
function a(){
console.log(this); //输出函数a中的this对象
}
function b(){}
var c={name:"call"}; //定义对象c
a.call(); //window
a.call(null); //window
a.call(undefined); //window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b); //function b(){}
a.call(c); //Object
function Animal(){
this.name="animal";
this.showName=function(){
console.log(this.name);
}
}
function Dog(){
this.name="dog";
}
var animal=new Animal();
var dog=new Dog();
animal.showName.call(dog);//dog
//意思是把animal的方法放到dog上执行,也可以说,把animal 的showName()方法放到 dog上来执行,所以this.name 应该是 dog
function Animal(name){
this.name=name;
this.showName=function(){
console.log(this.name);
}
}
function Dog(name){
Animal.call(this,name);
}
var dog=new Dog("Crazy dog");
dog.showName();//Crazy dog
//Animal.call(this) 的意思就是使用 Animal对象代替this对象,
//那么Dog就能直接调用Animal的所有属性和方法。类似继承。
2. apply
apply()
方法调用一个函数, 其具有一个指定的this
值,以及作为一个数组(或[类似数组的对象])提供的参数。
语法:apply([thisObj[,argArray]])
说明:如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
注意:call()方法的作用和 apply() 方法类似,只有一个区别,就是 call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组
既然两者功能一样,那该用哪个呢?
在JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call ;而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
/* min/max number in an array */
var numbers = [5, 6, 2, 3, 7];
/* using Math.min/Math.max apply */
/* This about equal to Math.max(numbers[0], ...) or Math.max(5, 6, ..) */
var max = Math.max.apply(null, numbers); 7
var min = Math.min.apply(null, numbers);1
var min = Math.min.call(null,5,6,2,3,7);1
1,函数之间的相互调用
function add(a,b){
alert(a+b);
}
function sub(a,b){
alert(a-b);
}
add.apply(sub,[5,6]); //11
add.call(sub,5,6); //11
从这里可以看出apply和call的参数方式是不一样的,
call的参数适合用于可明确值,且简短的参数,
apply的参数适合用于数组元素较多的场景。
2,构造函数之间的调用
function Person(){
this.age = 50;
this.showAge= function(){
alert(this.age);
}
}
function Son(){
this.age = 20;
}
var father = new Person();
var xiaoming = new Son();
father.showAge();//50
xiaoming.showAge();//xiaoming.showAge is not a function
xiaoming 是没有showAge方法的,那如果想要知道xiaoming的年龄呢?
father.showAge.apply(xiaoming) //立即执行显示20
father.showAge.call(xiaoming)//立即执行显示20
xiaoming.showAge();报错,会说showAge() is not a function
此时说明将方法应用于另一个对象时,仅仅是对另一个对象执行此方法,结束之后,该对象不拥有此方法。
那么如果想要另一个对象也拥有这个方法呢?
还是刚刚的例子,我们在Son方法中添加代码:
function Son(){
this.age = 20;
Person.call(this);
//Person.apply(this)
}
var xiaoming = new Son();
xiaoming.showAge();//50 注意这里还是50哦 不是20 想想为啥?
------------------------------------------------------------------
function Son(){
Person.call(this);
//Person.apply(this)
this.age = 20;
}
var xiaoming = new Son();
xiaoming.showAge();//20 知道为啥了吧
3. Javascript 没有私有方法的概念,想用闭包实现
(function () {
var Person = function () {
this.doSomeThing = function () {
_privateFunction.call(this);
}
}
var _privateFunction = function () {
}
window.Person = Person;
}).call(window);
差不多就是这个意思,callback的时候,
当你希望你的callback中的上下文是当前上下文的时候,也可以用call或者apply,有什么好处呢?
这个时候你的callback 里面的this 就是指代当前上下文。
例如一个类Person,然后他的方法 say 有一个callback的参数,
如果这个callback是通过普通的括号来执行的话,
那在这个callback里面执行person的其它方法还需要用person.other 来实现,
但是切换上下文之后,就是this.other搞定~代码对比如下:
var Person = function(){
};
Person.prototype.say = function(callback){
callback();
};
Person.prototype.other = function(){
};
var vincent = new Person();
vincent.say(function(){
vincent.other();
});
用了call的:
var Person = function(){
};
Person.prototype.say = function(callback){
callback.call(this);
};
Person.prototype.other = function(){
};
var vincent = new Person();
vincent.say(function(){
this.other();
});
3. bind
bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
注意:bind方法的返回值是函数
var bar=function(){
console.log(this.a);
}
var foo={
a:3
}
bar(); //undefined
bar.bind(foo)(); //3
/*或*/
var func=bar.bind(foo);
func(); //3