在JavaScript中,call迎瞧、apply和bind是Function對(duì)象自帶的三個(gè)方法夸溶,這三個(gè)方法的主要作用是改變函數(shù)中的this指向。
call凶硅、apply缝裁、bind方法的共同點(diǎn)和區(qū)別:
apply、call足绅、bind三者都是用來(lái)改變函數(shù)的this對(duì)象的指向的压语;
apply、call编检、bind三者第一個(gè)參數(shù)都是this要指向的對(duì)象胎食,也就是想指定的上下文(函數(shù)的每次調(diào)用都會(huì)擁有一個(gè)特殊值——本次調(diào)用的上下文(context)——這就是this關(guān)鍵字的值。)允懂;
apply厕怜、call、bind三者都可以利用后續(xù)參數(shù)傳參蕾总;
bind是返回對(duì)應(yīng)函數(shù)粥航,便于稍后調(diào)用;apply生百、call則是立即調(diào)用 递雀。
一、call
call( )
語(yǔ)法:
call ( [ thisObj [ ,arg1 [, arg2[ , [ ,.argN ] ] ] ] ] )
定義:調(diào)用一個(gè)對(duì)象的一個(gè)方法蚀浆,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象缀程。
說(shuō)明:call方法可以用來(lái)代替另一個(gè)對(duì)象調(diào)用一個(gè)方法搜吧。
call方法可將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。
thisObj的取值有以下4種情況:
(1) 不傳杨凑,或者傳null,undefined滤奈, 函數(shù)中的this指向window對(duì)象
(2) 傳遞另一個(gè)函數(shù)的函數(shù)名,函數(shù)中的this指向這個(gè)函數(shù)的引用
(3) 傳遞字符串撩满、數(shù)值或布爾類(lèi)型等基礎(chǔ)類(lèi)型蜒程,函數(shù)中的this指向其對(duì)應(yīng)的包裝對(duì)象,如 String伺帘、Number昭躺、Boolean
(4) 傳遞一個(gè)對(duì)象,函數(shù)中的this指向這個(gè)對(duì)象
function a( ) {
? ?console.log(this); ? ? ? ? ? ? ? //輸出函數(shù)a中的this對(duì)象
}
function b( ) { }
var c = {name:"call"}; ? ? ? ? ? //定義對(duì)象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
如果你不理解上面的伪嫁,沒(méi)關(guān)系窍仰,我們?cè)賮?lái)看一個(gè)例子:
function class1( ) {
? ? ? ? this.name=function ( ) {
? ? ? ? ? ? ?console.log("我是class1內(nèi)的方法");
? ? ? ?}
}
function class2 ( ) {
? ? ? ? ? class1.call(this); ? ? ? ? ? ? ? ?//此行代碼執(zhí)行后,當(dāng)前的this指向了class1
}
var f = new class2 ( );
f.name( ); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //調(diào)用的是class1內(nèi)的方法礼殊,將class1的name方法交給class2使用
常用例子:
(1)
function eat(x,y) {
? ? ? console.log(x+y);
}
function drink(x,y) {
? ? ? ?console.log(x-y);
}
eat.call(drink,3,2);
輸出:5
這個(gè)例子中的意思就是用 eat 來(lái)替換 drink,eat.call(drink,3,2) == eat(3,2) 针史,所以運(yùn)行結(jié)果為:console.log(5);
注意:js 中的函數(shù)其實(shí)是對(duì)象晶伦,函數(shù)名是對(duì) Function 對(duì)象的引用。
(2)
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
在上面的代碼中啄枕,我們可以看到Dog里并沒(méi)有showName方法婚陪,那為什么(this.name)的值是dog呢?
關(guān)鍵就在于最后一段代碼(animal.showName.call(dog))频祝,意思是把a(bǔ)nimal的方法放到dog上執(zhí)行泌参,也可以說(shuō),把a(bǔ)nimal 的showName()方法放到 dog上來(lái)執(zhí)行常空,所以this.name 應(yīng)該是 dog沽一。
(3)繼承
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對(duì)象代替this對(duì)象,那么Dog就能直接調(diào)用Animal的所有屬性和方法漓糙。
二铣缠、apply( )
語(yǔ)法:apply ( [ thisObj [ , argArray ] ] )
定義:應(yīng)用某一對(duì)象的一個(gè)方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象昆禽。
說(shuō)明:
?如果 argArray 不是一個(gè)有效的數(shù)組或者不是 arguments 對(duì)象蝗蛙,那么將導(dǎo)致一個(gè) TypeError。
?如果沒(méi)有提供 argArray 和 thisObj 任何一個(gè)參數(shù)醉鳖,那么 Global 對(duì)象將被用作 thisObj捡硅, 并且無(wú)法被傳遞任何參數(shù)。
call 和 apply的區(qū)別
對(duì)于 apply盗棵、call 二者而言壮韭,作用完全一樣北发,只是接受參數(shù)的方式不太一樣。
function class1 (args1,args2) {
? ? ? this.name=function(){
? ? ? ? ? ? ? console.log(args,args);
? ? ? }
}
function class2 ( ) {
? ? ? ?var args1 = "1";?
? ? ? ?var args2 = "2";
? ? ? ?class1.call (this,args1,args2);
? ? ? ?/*或*/
? ? ? ?class1.apply ( this,[ args1,args2 ] );?
}
var c = new class2 ( );
c.name( );
輸出:12
call需要把參數(shù)按順序傳遞進(jìn)去泰涂,而?apply?則是把參數(shù)放在數(shù)組里鲫竞。
既然兩者功能一樣,那該用哪個(gè)呢逼蒙?
在JavaScript 中从绘,某個(gè)函數(shù)的參數(shù)數(shù)量是不固定的,因此要說(shuō)適用條件的話(huà)是牢,當(dāng)你的參數(shù)是明確知道數(shù)量時(shí)用 call 僵井;而不確定的時(shí)候用 apply,然后把參數(shù) push 進(jìn)數(shù)組傳遞進(jìn)去驳棱。當(dāng)參數(shù)數(shù)量不確定時(shí)批什,函數(shù)內(nèi)部也可以通過(guò) arguments 這個(gè)數(shù)組來(lái)遍歷所有的參數(shù)。
三社搅、bind
bind 是在EcmaScript5中擴(kuò)展的方法(IE6,7,8不支持)
bind ( ) ?方法與 apply 和 call 很相似驻债,也是可以改變函數(shù)體內(nèi) this 的指向。
? ? ?MDN的解釋是:bind ( )?方法會(huì)創(chuàng)建一個(gè)新函數(shù)形葬,稱(chēng)為綁定函數(shù)合呐,當(dāng)調(diào)用這個(gè)綁定函數(shù)時(shí),綁定函數(shù)會(huì)以創(chuàng)建它時(shí)傳入bind ( )方法的第一個(gè)參數(shù)作為this笙以,傳入?bind ( )?方法的第二個(gè)以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時(shí)本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來(lái)調(diào)用原函數(shù)淌实。
注意:bind 方法的返回值是函數(shù)
var ba r= function ( ) {
? ? ? ?console.log(this.x);
}
var foo = {
? ? ? ? x:3
}
bar ( );
bar.bind (foo) ( );
/*或*/
var func = bar.bind(foo);
func( );
輸出:
undefined
3