我們經(jīng)常會碰到這樣一些問題:
- 代碼1
var Person={
name: "bob",
getName: function(){
console.log(this.name);
}
}
var getMyName = Person.getName;
getMyname(); //undefined
或者是這樣的問題:
- 代碼2
function Person(name){
this.nickname = name;
this.distractedGreeting = function() {
setTimeout(function(){
console.log("Hello, my name is " + this.nickname);
}, 500);
}
}
var alice = new Person('Alice');
alice.distractedGreeting();
//Hello, my name is undefined
在JavaScript中,this
的指向是在運(yùn)行函數(shù)時確定的彻犁,而不是定義函數(shù)時確定的叫胁。第一段代碼,因?yàn)?code>getMyName是在全局環(huán)境下運(yùn)行的袖裕,故this
指向的上下文為window
曹抬。
第二段代碼,setTimeout
的運(yùn)行環(huán)境同樣為全局急鳄,故this
指向的也是window
,返回值為undefined
谤民。
JavaScript新手經(jīng)常犯的一個錯誤,是將一個方法從對象中拿出來,然后再調(diào)用疾宏,希望方法中的this
是原來的對象张足。(比如在回調(diào)中傳入這個方法。)如果不做特殊處理的話坎藐,一般會丟失原來的對象为牍。
call
與apply
就是用來解決這個問題的。
call
我們首先來看call
的用法岩馍。以代碼1
為例:
var Person={
name: "bob",
getName: function(){
console.log(this.name);
}
}
var getMyName = Person.getName;
getMyName.call(Person); //bob
通過call
方法碉咆,我們成功地讓getMyName
方法輸出了bob。call
方法的作用蛀恩,簡單來說疫铜,就是改變執(zhí)行函數(shù)的this指向。它可以讓執(zhí)行函數(shù)的執(zhí)行環(huán)境指向call
第一個參數(shù)的環(huán)境下双谆。
call
方法可以有多個參數(shù)壳咕。第一個參數(shù)以外的參數(shù),是傳給執(zhí)行函數(shù)的傳參顽馋。以代碼1
為例:
var Person={
name: "bob",
getName: function(a,b){
console.log(this.name+' '+a+' '+b);
}
}
var getMyName = Person.getName;
getMyName.call(Person,2,'abc'); //bob 2 abc
apply
apply
方法與call非常相似谓厘。同樣是改變執(zhí)行函數(shù)的this指向,apply
方法和call
方法在使用方法上幾乎沒有什么區(qū)別寸谜。
以代碼1
為例:
var Person={
name: "bob",
getName: function(){
console.log(this.name);
}
}
var getMyName = Person.getName;
getMyName.apply(Person); //bob
在執(zhí)行函數(shù)沒有傳參時竟稳,從代碼上看,我們幾乎看不出差別,僅僅是把call換成了apply住练。
他們之間唯一的不同地啰,就是apply只有兩個參數(shù)愁拭,第二個參數(shù)必須是一個數(shù)組讲逛,執(zhí)行函數(shù)的傳參,以數(shù)組的形式傳遞岭埠。而call的傳參盏混,必須一個一個傳入。
以代碼1
為例:
var Person={
name: "bob",
getName: function(a,b){
console.log(this.name+' '+a+' '+b);
}
}
var getMyName = Person.getName;
getMyName.apply(Person,[2,'abc']); //bob 2 abc
需要注意的是惜论,如果call
和apply
的第一個參數(shù)寫的是null
许赃,那么this
指向的是window
對象。
以代碼1
為例:
var Person={
name: "bob",
getName: function(){
console.log(this.name);
}
}
var getMyName = Person.getName;
getMyName.apply(null); //Window
bind
最后我們來說說bind
馆类。
bind
方法會創(chuàng)建一個新函數(shù),稱為綁定函數(shù)混聊。當(dāng)調(diào)用這個綁定函數(shù)時,綁定函數(shù)會以創(chuàng)建它時傳入bind
方法的第一個參數(shù)作為 this
,傳入bind
方法的第二個以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。
代碼2
以前的解決辦法乾巧,通常是緩存this
句喜。
function Person(name){
this.nickname = name;
this.distractedGreeting = function() {
var self = this; // <-- 注意這一行!
setTimeout(function(){
console.log("Hello, my name is " + self.nickname); // <-- 還有這一行!
}, 500);
}
}
var alice = new Person('Alice');
alice.distractedGreeting();
// after 500ms logs "Hello, my name is Alice"
而我們使用bind
方法,能更簡單明了地解決這個問題沟于。
function Person(name){
this.nickname = name;
this.distractedGreeting = function() {
setTimeout(function(){
console.log("Hello, my name is " + this.nickname);
}.bind(this), 500); // <-- this line!
}
}
var alice = new Person('Alice');
alice.distractedGreeting();
// after 500ms logs "Hello, my name is Alice"
代碼1
的問題同樣可以用bind
方法來解決咳胃。
var Person={
name: "bob",
getName: function(){
console.log(this.name);
}
}
var getMyName = Person.getName;
var bindGetName = getMyName.bind(Person);
getMyName();//bob
這里我們需要注意的是,bind
與call
和apply
的不同之處旷太,就是bind
返回的是一個修改過后的函數(shù)展懈。
剛才提到了,bind
方法同樣可以有多個參數(shù)供璧。
以代碼1
為例:
var Person={
name: "bob",
getName: function(a,b,c,d){
console.log(this.name+' '+a+' '+b+' '+c+' '+d);
}
}
var getMyName = Person.getName;
var bindGetName = getMyName.bind(Person,12,34);
bindGetName('ab','cd');//bob 12 34 ab cd
可以看到存崖,傳入bind
方法的第二個以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。
最后睡毒,我們來總結(jié)一下:(敲黑板来惧,這里是你們要的重點(diǎn)!B类帧)
- 用途:都是在特定的作用域中調(diào)用函數(shù)违寞,實(shí)際上等于設(shè)置函數(shù)體內(nèi)this對象的值。
-
apply
接受兩個參數(shù):一個是在其中運(yùn)行函數(shù)的作用域偶房,另一個是參數(shù)數(shù)組趁曼。參數(shù)數(shù)組可以是arguments對象。 -
call
與apply
的區(qū)別僅在于接受參數(shù)的方式不同棕洋。call
的參數(shù)必須逐個列舉出來挡闰。 - 重要用途:能夠擴(kuò)充函數(shù)賴以運(yùn)行的作用域。 對象與方法間不需要有任何耦合關(guān)系。
-
bind
方法會創(chuàng)建一個函數(shù)的實(shí)例摄悯,其this
值會被綁定到傳給bind
函數(shù)的值赞季。 - 傳入
bind
方法的第二個以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。