函數(shù)是JavaScript
世界里的第一公民,換句話來說,就是我們?nèi)绻梢跃?/span>
JavaScript
函數(shù)的使用,那么對
JavaScript
的運用可以更游刃有余了。熟悉
JavaScript
的人應(yīng)該都知道,同樣的函數(shù),以不同的方式調(diào)用的話,受影響最大的應(yīng)該是
this
。下面我們來說說
JavaScript
函數(shù)的各種調(diào)用模式,希望對大家
學習javascript有所幫助。
一、普通函數(shù)的調(diào)用模式
所謂普通函數(shù)的調(diào)用模式,也是JavaScript
函數(shù)的最簡單的一種調(diào)用模式,直接就是函數(shù)名后接一個
()
實現(xiàn)調(diào)用,看下面代碼:
function
func(){
console.log(
this === window); //true
}
func();
上面代碼,我們用function
關(guān)鍵字聲明了一個
func
函數(shù),并且在函數(shù)體內(nèi)打印
this===window
,然后我們直接調(diào)用函數(shù)
func
,我們可以看到控制臺是直接打印出
true
,也就是說, 函數(shù)的這種普通調(diào)用模式,函數(shù)體內(nèi)的
this
是指向全局環(huán)境
window
的 。不清楚這點的同學,可以能會遇到這樣的一個
bug
:
var color = 'gg';
var obj = {
color : 'red',
show :
function(){
function
func1(){
console.log(
this.color); //gg
}
func1();
}
}
obj.show();
我們在全局環(huán)境下聲明了一個變量 color
和一個對象
obj
,在對象
obj
里面我們還聲明了一個
color
屬性 為
'red'
,一個
show
方法。而且在
show
方法里面呢,我們還聲明了一個函數(shù)
func1
并且調(diào)用了
func1
,
func1
的作用是打印
this.color
。最后我們運行代碼
obj.show();
調(diào)用
obj
里面的
show
方法。不清楚函數(shù)的普通調(diào)用模式的特點的同學可能會認為此時在控制臺答應(yīng)出來的會是
'red'
。實際上此時在控制臺答應(yīng)出來的應(yīng)該是
gg
。因為函數(shù)
func1
的調(diào)用模式是 普通函數(shù)調(diào)用模式(即使它是在
obj
的
show
方法里面調(diào)用的),所以此時函數(shù)體內(nèi)的
this
是指向 全局環(huán)境
window
的,所以就打印了全局環(huán)境下的變量
color
。
可能有些同學會問:如果我們希望 func1
函數(shù)打印出來的是
'red'
呢,應(yīng)該怎么改?其實很簡單,因為
obj.color
才是
'red'
,所以我們只需要把
指向
obj
的
this
引入到函數(shù)
func1
里面就行了:
var color = 'gg';
var obj = {
color : 'red',
show :
function(){
var that =
this;
function
func1(){
console.log(that.color); //red
}
func1();
}
}
obj.show();
在上面的代碼中,因為 show
里面的
this
指向
obj
的,所以我們在
show
里面聲明一個變量
that = this;
用來把指向
obj
的
this
引入到
func1
中,然后再把
func1
函數(shù)體內(nèi)的
this.color
改為
that.color ,
此時在控制臺打印出來的就是我們想要的
'red'
了。
可能現(xiàn)在又有同學會問:為什么 show
里面的
this
是指向
obj
的呢?這就是我們要說的
JavaScript
函數(shù)的第二種調(diào)用模式:方法調(diào)用模式
二、方法調(diào)用模式
方法調(diào)用模式,簡單來說就是把一個 JavaScript
函數(shù)作為一個對象的方法來調(diào)用,當一個函數(shù)被保存為一個對象的屬性是,我們就把它稱為方法,例如上文的
obj
對象里的
show
, 當一個方法被調(diào)用時,函數(shù)體里面的
this
就會綁定到這個對象 ,例如上文的
show
里面的
this
。方法調(diào)用模式也很容易辨別:
obj.show()
,對象名
.
屬性名
()
;代碼的話可以參考上文的
obj
代碼 ,博主就不多寫了。記?。?方法的調(diào)用是可以在函數(shù)體內(nèi)通過
this
訪問自己所屬的那個對象的。
三、構(gòu)造器調(diào)用模式
博主認為構(gòu)造器調(diào)用模式是相對于其他模式來說較為復雜點的調(diào)用模式了。通過關(guān)鍵字 new
可以把一個函數(shù)作為構(gòu)造器來調(diào)用。關(guān)鍵字
new
可以改變函數(shù)的返回值:
function
func2(
name){
this.name = name;
}
name; //undefined
//
普通函數(shù)調(diào)用模式
var foo = func2('afei');
foo; //undefined
name; //afei
//
構(gòu)造器調(diào)用模式
var bar = new func2('lizefei');
bar.__proto__ === func2.prototype; //true
bar; //{name:'lizefei'}
bar.
name; //'lizefei'
在上示代碼中我們聲明了一個函數(shù) func2
,分別用兩種不同的調(diào)用模式去調(diào)用它。因為函數(shù)
func2
并沒有顯式返回值,所以作為普通函數(shù)去調(diào)用時,它什么也沒有返回,所以
foo
的值是
undefined
。因為普通調(diào)用模式的
this
是指向 全局環(huán)境
window
的,所以
func2('afei');
后,全局環(huán)境下就多了一個
name
變量且等于
'afei'
。
func2
作為構(gòu)造器調(diào)用時,我們可以看到,它返回的是一個對象,因為關(guān)鍵字
new
使得函數(shù)在調(diào)用是發(fā)生了如下的特殊變化:
1.
創(chuàng)建了一個新對象,而且這個新對象是鏈接到
func2
的
prototype
屬性的
2.
把函數(shù)里的
this
指向了這個新對象
3.
如果沒有顯式的返回值,新對象作為構(gòu)造器
func2
的返回值進行返回(所以
bar
是
{name:'lizefei'}
)
這樣子我們就可以看出構(gòu)造器的作用:通過函數(shù)的調(diào)用來初始化新創(chuàng)建出來的對象。在JavaScript
的面向?qū)ο缶幊汤锩?,這個可是相當重要的。
因為在函數(shù)的聲明上,在未來作為構(gòu)造器調(diào)用的函數(shù)和普通函數(shù)的聲明沒什么區(qū)別,所以導致后來的開發(fā)者很容易因為調(diào)用模式的錯誤導致程序出問題。所以開發(fā)者們都默契地約定,
用來做構(gòu)造器調(diào)用的函數(shù)的函數(shù)名的第一個字符應(yīng)該大寫
,例如:Person
,
People
。這樣子后來的開發(fā)者一看到函數(shù)名就知道要用構(gòu)造器調(diào)用模式調(diào)用此函數(shù)了。
四、使用apply()和call()方法調(diào)用
這種調(diào)用的模式是為了更靈活控制函數(shù)運行的上下文環(huán)境而誕生的。簡單的說就是為了靈活控制函數(shù)體內(nèi) this
的值。
apply
和
call
這兩個方法的第一個參數(shù)都是要傳遞被函數(shù)上下文的對象(簡單點說就是要綁定給函數(shù)
this
的對象)。其他參數(shù)就有所不同了:
apply
方法的第二個參數(shù)是一個數(shù)組,數(shù)組里面的值將作為函數(shù)調(diào)用的參數(shù);
call
方法,從第二個參數(shù)起(包括第二個參數(shù)),剩下的參數(shù)都是作為函數(shù)調(diào)用的參數(shù);
讓我們看看栗子:
var obj = {
name :'afei'
}
function
say(ag1,ag2){
console.log(ag1+':'+ag2+" "+
this.name);
}
say.apply(obj,['apply
方法
','hello']); //apply
方法
:hello afei
say.call(obj,'call
方法
','hi'); //call
方法
:hi afei
正如栗子所示,我們把對象 obj
作為函數(shù)
say
的上下文來調(diào)用函數(shù)
say
,所以函數(shù)里的
this
是指向 對象
obj
的。在
apply
方法里,我們通過數(shù)組
['apply
方法
','hello']
給
say
方法傳遞了兩個參數(shù)(
'apply
方法
'
和
'hello'
),所以打印出來是:
apply
方法
:hello afei
。
同理 call
也是一樣,而且函數(shù)傳遞的方式通過上面的代碼也一目了然我,博主就不多做解釋了。
另外,博主還聽說apply
和
call
這兩個方法除了傳遞參數(shù)的方式不一樣,執(zhí)行的速度還是
apply
比
call
要快呢。不過博主就沒有實驗過。
五、總結(jié)
在JavaScript
里面,函數(shù)只要的調(diào)用模式就是這幾種了(在
ES6
里面還有一種很奇怪很特殊的函數(shù)調(diào)用模式,叫做
’
標簽?zāi)0?/span>
‘
,在這里博主也不多說了,有空另更),只要掌握了這幾種主要的調(diào)用模式,那么日后再也不用擔心
this
的值變來變?nèi)チ恕?/span>
來源:
博客園