當前位置:
首頁 > 知識 > JavaScript函數的各種調用模式

JavaScript函數的各種調用模式

函數是JavaScript世界裡的第一公民,換句話來說,就是我們如果可以精通JavaScript函數的使用,那麼對JavaScript的運用可以更遊刃有餘了。熟悉JavaScript的人應該都知道,同樣的函數,以不同的方式調用的話,受影響最大的應該是 this 。下面我們來說說JavaScript函數的各種調用模式。

一、普通函數的調用模式

所謂普通函數的調用模式,也是JavaScript函數的最簡單的一種調用模式,直接就是函數名後接一個 實現調用,看下面代碼:

function func{
console.log(this === window); //true
}
func;

上面代碼,我們用function關鍵字聲明了一個 func 函數,並且在函數體內列印 this===window,然後我們直接調用函數func,我們可以看到控制台是直接列印出 true ,也就是說,函數的這種普通調用模式,函數體內的 this 是指向全局環境 window 的。不清楚這點的同學,可以能會遇到這樣的一個bug:

var color = "gg";
var obj = {
color : "red",
show : function{
function func1{
console.log(this.color); //gg
}
func1;
}
}
obj.show;

我們在全局環境下聲明了一個變數 color 和一個對象 obj ,在對象 obj 裡面我們還聲明了一個 color 屬性 為 "red",一個 show 方法。而且在 show 方法裡面呢,我們還聲明了一個函數 func1 並且調用了 func1,func1 的作用是列印 this.color。最後我們運行代碼 obj.show; 調用obj裡面的show方法。不清楚函數的普通調用模式的特點的同學可能會認為此時在控制台答應出來的會是 "red" 。實際上此時在控制台答應出來的應該是 gg 。因為函數 func1 的調用模式是 普通函數調用模式(即使它是在 obj 的 show 方法裡面調用的),所以此時函數體內的 this 是指向 全局環境window 的,所以就列印了全局環境下的變數 color 。

可能有些同學會問:如果我們希望 func1 函數列印出來的是 "red" 呢,應該怎麼改?其實很簡單,因為 obj.color 才是 "red" ,所以我們只需要把 指向 obj 的 this 引入到函數 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 函數體內的 this.color 改為 that.color ,此時在控制台列印出來的就是我們想要的 "red" 了。

可能現在又有同學會問:為什麼 show 裡面的 this 是指向 obj 的呢?這就是我們要說的JavaScript函數的第二種調用模式:方法調用模式

二、方法調用模式

方法調用模式,簡單來說就是把一個 JavaScript函數作為一個對象的方法來調用,當一個函數被保存為一個對象的屬性是,我們就把它稱為方法,例如上文的 obj 對象里的 show ,當一個方法被調用時,函數體裡面的 this 就會綁定到這個對象,例如上文的 show 裡面的 this 。方法調用模式也很容易辨別:obj.show,對象名 . 屬性名 ;代碼的話可以參考上文的 obj 代碼 ,博主就不多寫了。記住:方法的調用是可以在函數體內通過 this 訪問自己所屬的那個對象的。

三、構造器調用模式

博主認為構造器調用模式是相對於其他模式來說較為複雜點的調用模式了。通過關鍵字 new 可以把一個函數作為構造器來調用。關鍵字 new 可以改變函數的返回值:

function func2(name){
this.name = name;
}

name; //undefined

//普通函數調用模式
var foo = func2("afei");
foo; //undefined
name; //afei

//構造器調用模式
var bar = new func2("lizefei");
bar.__proto__ === func2.prototype; //true bar; //{name:"lizefei"} bar.name; //"lizefei"

在上示代碼中我們聲明了一個函數 func2 ,分別用兩種不同的調用模式去調用它。因為函數 func2 並沒有顯式返回值,所以作為普通函數去調用時,它什麼也沒有返回,所以 foo 的值是 undefined 。因為普通調用模式的 this 是指向 全局環境 window 的,所以 func2("afei"); 後,全局環境下就多了一個 name 變數且等於 "afei"。

func2 作為構造器調用時,我們可以看到,它返回的是一個對象,因為關鍵字 new 使得函數在調用是發生了如下的特殊變化:

  1. 創建了一個新對象,而且這個新對象是鏈接到 func2 的 prototype 屬性的
  2. 把函數里的 this 指向了這個新對象
  3. 如果沒有顯式的返回值,新對象作為構造器func2的返回值進行返回(所以bar 是 {name:"lizefei"})

這樣子我們就可以看出構造器的作用:通過函數的調用來初始化新創建出來的對象。在JavaScript的面向對象編程裡面,這個可是相當重要的。

因為在函數的聲明上,在未來作為構造器調用的函數和普通函數的聲明沒什麼區別,所以導致後來的開發者很容易因為調用模式的錯誤導致程序出問題。所以開發者們都默契地約定,用來做構造器調用的函數的函數名的第一個字元應該大寫,例如:Person,People。這樣子後來的開發者一看到函數名就知道要用構造器調用模式調用此函數了。

四、使用apply和call方法調用

這種調用的模式是為了更靈活控制函數運行的上下文環境而誕生的。簡單的說就是為了靈活控制函數體內 this 的值。

apply 和 call這兩個方法的第一個參數都是要傳遞被函數上下文的對象(簡單點說就是要綁定給函數 this 的對象)。其他參數就有所不同了:

apply方法的第二個參數是一個數組,數組裡面的值將作為函數調用的參數;

call方法,從第二個參數起(包括第二個參數),剩下的參數都是作為函數調用的參數;

讓我們看看栗子:

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 作為函數 say 的上下文來調用函數 say ,所以函數里的 this 是指向 對象 obj 的。在apply方法里,我們通過數組 ["apply方法","hello"] 給 say 方法傳遞了兩個參數("apply方法" 和 "hello"),所以列印出來是: apply方法:hello afei。

同理 call 也是一樣,而且函數傳遞的方式通過上面的代碼也一目了然我,博主就不多做解釋了。

另外,博主還聽說apply和call這兩個方法除了傳遞參數的方式不一樣,執行的速度還是apply 比 call 要快呢。不過博主就沒有實驗過。

五、總結

在JavaScript裡面,函數只要的調用模式就是這幾種了(在ES6裡面還有一種很奇怪很特殊的函數調用模式,叫做』標籤模板『,在這裡博主也不多說了,有空另更),只要掌握了這幾種主要的調用模式,那麼日後再也不用擔心 this 的值變來變去了。

上文如果有漏的、有錯誤的地方,望各位小夥伴指出,小弟虛心向學。

ps:轉載請標明出處 http://www.cnblogs.com/afeihome/

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

JavaScript深入淺出補充——(一)數據類型,表達式和運算符
mac下git配置和jenkins打包
「HK」的日常之ARP斷網攻擊
使用kuberspay無坑安裝生產級Kubernetes集群
框架基礎:ajax設計方案(五)——集成promise規範,更優雅的書寫代碼

TAG:科技優家 |

您可能感興趣

加入Transformer-XL,這個PyTorch包能調用各種NLP預訓練模型
使用redis來調用iptables,封禁惡意IP
c井動態調用WebService
jQuery UI 小部件(Widget)方法調用
使用 python 調用 echart 畫圖
SpringCloud之服務提供與調用(Ribbon,Feign)
Asp.Net Core使用SignalR進行服務間調用
python訓練mask rcnn模型&&C++調用訓練好的模型——基於opencv4.0
necp_client_action系統調用中的堆溢出漏洞分析
如何用Ptrace攔截並模擬Linux系統調用
關於如何使用webpack命令行傳入變數,並通過process.env來調用
python調用api介面
C/C++ 使用 TensorFlow 預訓練好模型——間接調用 Python 實現
dubbo+zipkin調用鏈監控
OpenCV調用TensorFlow是什麼意思
通過調用Windows命令,將chm 文件轉換為html 文件
透過現象看原理:詳解 Spring 中 Bean 的 this 調用導致 AOP 失效的原因
Python 調用 Micro 宏自動解析 Nmon 文件進行數據歸檔
Alexa應用開發者將可免費調用8種Amazon Polly自然語音
Flutter調用平台代碼