在JavaScript中,call
、apply
和bind
是Function
对象自带的三个方法,这三个方法的主要作用是改变函数中的this
指向。
一、方法定义
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指向这个对象
apply方法:
语法:apply([thisObj[,argArray]])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
call 和 apply的区别
对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。
bind方法:
语法:bind([thisObj[,arg1[, arg2[, [,.argN]]]]])() 或者
bind([thisObj[,argArray]])()
定义:bind()
方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()
方法的第一个参数作为 this
,传入 bind()
方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
说明:bind
是在EcmaScript5中扩展的方法(IE6,7,8不支持),bind()
方法与 apply 和 call 很相似,也是可以改变函数体内 this
的指向。
注意:bind
方法的返回值是函数。
二、常用实例
1、函数也是对象,函数的调用替换用法:
function add(a,b){
alert(a+b);
}
function sub(a,b){
alert(a-b);
}
//call的用法
add.call(sub,3,1); //alert(4)
//apply的用法
add.apply(sub,[3,1]); //alert(4)
//bind的用法
add.bind(sub,3,1)(); //alert(4)
add.bind(sub,[3,1])(); //alert(3,1undefined)
通过call、apply或bind方法,用 add 来替换 sub方法。
2、对象的方法调用替换用法:
function Animal(){
this.name = "Animal";
this.showName = function(){
alert(this.name);
}
}
function Dog(){
this.name = "Dog";
}
var animal = new Animal();
var dog = new Dog();
//call的用法
animal.showName.call(dog,“”); //alert(Dog)
//apply的用法
animal.showName.apply(dog,[]); //alert(Dog)
//bind的用法
animal.showName.bind(dog,“”)(); //alert(Dog)
animal.showName.bind(dog,[])(); //alert(Dog)
通过call、apply或bind方法,将原本属于Animal对象的showName()方法交给对象dog来使用了。
3、实现继承:
function Animal(name){
this.name = name;
this.showName = function(){
alert(this.name);
}
}
//call的用法
function Dog(name){
Animal.call(this, name)
}
var dog = new Dog("Dog");
dog.showName(); //alert(Dog)
//apply的用法
function Dog2(name){
Animal.apply(this, [name])
}
var dog2 = new Dog2("Dog");
dog2.showName(); //alert(Dog)
//bind的用法
function Dog3(name){
Animal. bind(this, name)()
}
var dog3 = new Dog3("Dog");
dog3.showName(); //alert(Dog)
function Dog4(name){
Animal. bind(this, [name])()
}
var dog4 = new Dog4("Dog");
dog4.showName(); //alert(Dog)
4、多重继承的实现
function Animal(name){
this.name = name;
this.showName = function(){
alert(this.name);
}
}
function Pet(food){
this.food = food;
this.loveEat = function(){
alert(this.food);
}
}
//这里只写一下call的用法 ,apply和bind的用法大家可以自己写一下
function Dog(name,food){
Animal.call(this, name);
Pet.call(this, food);
}
var dog = new Dog("Dog","Bone");
dog.showName(); //alert(Dog)
dog.loveEat(); //alert(Bone)
5、列举常用的一些方法
为了巩固加深记忆,下面列举一些常用用法:
a.数组之间追加
var array1 = [12 , "foot" , {name:"tom"} , true];
var array2 = ["Do" , 123 , 456, false];
Array.prototype.push.apply(array1, array2);
array1 的值为:[12, "foot", {name:"tom"}, true, "Do", 123, 456, false]
b.获取数组中的最大值
var numbers = [3, 4 , 5 , -9 ];
var maxInNumbers = Math.max.apply(Math, numbers); //5
console.log(maxInNumbers);
maxInNumbers = Math.max.call(Math,3, 4 , 5 , -9 ); //5
console.log(maxInNumbers);
number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。最小值也是一样的实现方式。
c.验证是否是数组(前提是toString()方法没有被重写过)
function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
var a = [1,2,3,4,55];
isArray(a); //true
d.类(伪)数组使用数组方法
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("div"));
Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。