深入理解 JavaScript 中的函式
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃!
本文旨在提供web開發人員必須瞭解的所有JavaScript函式的基本知識。
函式於軟體開發者而言並不是什麼奇幻世界。如果你的日常活動涉及到編碼,哪怕是一點點,那麼在一天結束的時候,你一定建立/修改了一個或多個函式。
簡而言之函式只不過是一組執行某個操作的語句。函式可能會有一些輸入引數(在函式體中使用),並在執行後返回值。
JavaScript函式也具有這些特性,但它們不僅僅是常規函式。JavaScript函式是物件。你可以檢視我曾經寫的關於JavaScript物件的文章,裡面我提到幾乎JavaScript中的所有一切都是物件。
作為物件,JavaScript函式可能會有屬性和其他函式(方法)。讓我們來看看JavaScript中的一個典型的函式定義。
function myNotSoGreatFunc(visitor) { console.log("Welcome to Code Morning Mr. " + visitor); }
沒錯。上面的函式不涉及什麼巨集偉大業,因為它僅是對部落格訪問者表示了歡迎。但它展示了JavaScript函式的樣子。函式定義從關鍵字function
開始,然後是函式名,空的或有引數的括號。實際的函式程式碼(JavaScript語句)被封裝在一對花括號內{ }。對於函式而言,return
語句是可選的。JavaScript函式總是會返回一個值。當function
主體中沒有return
語句時,那麼function
返回undefined。
下面的程式碼呼叫傳遞visitor name作為引數的函式。
myNotSoGreatFunc("Bob Martin"); // Output: // Welcome to Code Morning Mr. Bob Martin.
到現在為止,我們瞭解了函式非常基本的特徵。現在,我們將對JavaScript函式的一些高階概念一探究竟。
匿名函式
JavaScript函式可以是匿名的。這意味著你可以從函式宣告中省略函式名。但是,函式必須儲存在變數中。
var addNumbers = function (x, y) { return x + y; }
上述語法被也被稱為函式表示式。你可以把變數addNumbers
當作函式名,以及像下面這樣呼叫該函式。
var sum = addNumbers(2, 3);
當你想傳遞一個函式作為引數給另一個函式時,函式表示式就非常方便了。讓我們用一個簡單的例子來試著瞭解這一點。
var add = function (first, second) { return first + second }; var multiply = function (first, second) { return first * second }; function calculate(fun, a, b) { return fun(a, b); }
首先我已經建立了兩個匿名函式。第一個返回兩個數的加法運算,第二個返回兩個數的乘法運算。相當簡單,沒有什麼可值得炫耀的地方。然後,我定義函式calculate
,這個函式接受函式作為第一個引數後跟兩個引數接受兩個數字。
我可以通過傳遞任意函式作為第一個引數來呼叫函式calculate。
var sum = calculate(add, 2, 3); // sum = 5 var multiplication = calculate(multiply, 2, 3); // multiplication = 6
你可以看到將函式作為引數傳遞是多麼容易。這種模式在AJAX中大量使用,當你在AJAX呼叫完成後,傳遞迴調函式處理成功或失敗的場景時。
關於引數的更多內容
JavaScript是非常靈活的,當涉及到傳遞或訪問函式引數的時候。讓我們看一下函式引數可以被操縱的方式。
缺少引數
呼叫函式時,函式的引數數量可以比要求的更少或更多。如果你呼叫的函式的引數比宣告的少,那麼缺少的引數被設定為undefined。
function callMe(a, b, c) { console.log("c is " + typeof c); } callMe("Code", "Morning"); // Output: "c is undefined" callMe("Learn", "JavaScript", "Functions"); // Output: "c is string"
Arguments物件
所有的JavaScript函式有一個特殊的物件,叫做arguments
,它是在函式呼叫過程中傳遞的引數陣列。該物件可以被用來訪問單個引數或獲得傳遞到函式的引數總數。
function callMe() { var i; for (i = 0; i < arguments.length; i++) { console.log(arguments[i]); } console.log("Total arguments passed: " + arguments.length); }
此函式假設沒有傳遞任何引數,但就像我說的,你可以傳遞任何數量的引數到JavaScript函式。我可以像這樣呼叫這個函式:
callMe("Code", "Morning", "Mr. Programmer"); // Output": // Code // Morning // Mr. Programmer // Total arguments passed: 3
每個引數可以從arguments
物件作為一個陣列項被訪問。被傳遞給函式的arguments
的總數可從arguments.length屬性獲得。
預設引數
你是C ++或C#程式設計師嗎?你見過使用預設引數的函式嗎?也許你會回答yes! ECMAScript 6帶來了JavaScript的這一特性,就是你可以定義帶有預設引數的函式。
function greetMyVisitors(name, profession = "The cool programmer") { alert("Welcome Mr. " + name + ", " + profession); }
該函式有禮貌地地迎接了部落格訪問者。它有兩個引數name
和profession
,並在訊息框中顯示一個歡迎訊息。如果在呼叫過程中沒有引數(或“undefined”)傳遞,那麼第二個引數取用預設值。
greetMyVisitors("Justin Bieber", "The singer"); // Shows the message "Welcome Mr. Justin Bieber, The singer" greetMyVisitors("Bob Martin"); // Shows the message "Welcome Mr. Bob Martin, The cool programmer" greetMyVisitors("John Papa", undefined); // Shows the message "Welcome Mr. John Papa, The cool programmer"
巢狀函式
函式可以在它的內部包含一個或多個函式。內部函式可能會在內部再次包含函式。讓我們來看看以下操作。
function wakeUpAndCode() { function wakeUp() { console.log("I just woke up"); } function code() { console.log("I am ready to code now"); } wakeUp(); code(); } wakeUpAndCode(); // Output: // I just woke up // I am ready to code now
函式wakeUpAndCode
包含兩個內部函式wakeUp
和code。當呼叫wakeUpAndCode時,函式主體開始執行函式主體。在外部函式中只有兩個可執行語句,呼叫wakeUp
和code
的方法。呼叫wakeUp
將執行內部wakeUp
函式,這將寫入string
“I just woke up”到控制檯。呼叫code
將會寫入“I am ready to code now”string
到控制檯。
內部函式可以訪問所有外部函式的變數和引數。內部函式是函式內部某種private
實現,並且不能從外部函式以外被呼叫。內部函式的使用生成了JavaScript閉包,這個我將另起一篇文章討論。
立即執行函式表示式(IIFE,發音iffy)
IIFE是被立即呼叫執行的匿名函式表示式。IIFE看上去像這樣:
(function() { // Your awesome code here }());
所有你要做的就是建立一個匿名函式,在函式定義後馬上放一對圓括號以呼叫函式,最後將所有程式碼封裝在另一對圓括號中。最外層的括號將它裡面的所有一切轉變成一個表示式,因為括號不能包含JavaScript語句。函式定義後面的圓括號則立即呼叫函式。
IIFE塊中定義的任何變數或函式對塊而言是本地的,並且不能被這個範圍以外的任何程式碼改變。
看看IIFE的這個例子。此函式沒有呼叫也會自動執行。
(function() { console.log("I run on my own."); }());
只需在plunker中複製並貼上程式碼,看看在瀏覽器控制檯中的輸出。如果你不知道去哪裡找瀏覽器控制檯,那麼只要在瀏覽器視窗中按下F12就會出現開發者工具。跳轉console選項卡以檢視console.log語句的所有輸出。
IIFE是一個在程式碼中建立區域性範圍的很好方法。它們可以幫助你保護變數和函式,以避免被應用程式的其他部分更改或覆蓋。JavaScript中IIFE的其他優勢?它們是如何解決全域性範圍汙染問題的?歡迎點選檢視我關於立即執行函式表示式的文章。
建構函式
函式可以充當構造器的角色,並且可以使用建構函式來建立新的物件。這是使JavaScript物件導向的特點之一。使用建構函式的好處是,你將能夠通過預定義的屬性和方法,創造儘可能多的物件。如果你由此關聯到其他語言中的類和物件,那麼你做的對。
讓我們建立一個帶有一些屬性和方法的建構函式Programmer
。你可以假設它在你最喜歡的語言中是一個類。
function Programmer(name, company, expertise) { this.name = name; this.company = company; this.expertise = expertise; this.writeCode = function() { console.log("Writing some public static thing.."); } this.makeSkypeCall = function() { console.log("Making skype call.."); } this.doSalsa = function() { console.log("I'm a programmer, I can only do Gangnam style.."); } this.canWriteJavaScript = function() { return expertise === "JavaScript"; } }
函式有三個引數,並建立了一個具有三個屬性和四種方法的物件。我不認為上面的程式碼需要任何解釋。此外,我可以建立任意數量程式設計師物件。
var javaProgrammer = new Programmer("Mohit Srivastava", "Infosys", "Java"); var dotnetProgrammer = new Programmer("Atul Mishra", "Prowareness", ".NET");
雖然也可以建立一個使用物件文字語法帶有相同屬性和方法的物件,但我們需要多次編寫相同的程式碼,這可不是什麼偉大的實踐。如果你知道程式設計DRY原則,那麼你就不會不贊同我。建構函式使得可以一次定義物件,並建立真正的例項,無論什麼時候你想要。
警告!
始終使用new關鍵字來從構造器建立新的物件。忘記了new
而像這個建立一個例項->
var jsProgrammer = Programmer("Douglas Crockford", "Yahoo", "JavaScript")
最終將新增所有屬性和方法到全域性的window
物件,哇哦,這將是太可怕了。原因是,除非明確指定,否則“this”指向全域性的window
物件。使用new
設定“this”上下文到被建立的當前物件。
然而,有一種變通方法可以來克服這個問題。你可以改變建構函式的實現以使域安全,然後在建立新的物件時,你就可以愉快地忽略new
關鍵字了。請參見以下修改了的建構函式程式碼。為了便於檢視,我已刪除了一些方法。
function Programmer(name, company, expertise) { if(!(this instanceof Programmer)) { return new Programmer(name, company, expertise); } this.name = name; this.company = company; this.expertise = expertise; this.writeCode = function() { console.log("Writing some public static thing.."); } }
if
條件檢查了this
物件是否是Programmer的一個例項。如果不是,它會建立一個新的Programmer
物件,並通過再次呼叫構造器返回相同的內容。
注意:你無法在不使用’new’關鍵字的情況下,在Strict
模式下從構造器建立一個新的物件。Strict
模式強制一些編碼準則,並且在你寫的東西不安全的情況下會丟擲錯誤。要啟用Strict
模式,你只需要新增在你的程式碼開頭新增字串 ‘use strict
’。在Strict模式下執行程式碼是一個良好的實踐。
'use strict' function doSomething() { ... } .... ....
在這篇文章中,我幾乎已經涵蓋了有關函式的所有內容。函式被認為是JavaScript中的一等公民。理解函式可能是最重要的事情,如果你想掌握JavaScript的話。
歡迎各位指正。
譯文連結:http://www.codeceo.com/article/javascript-function-coding.html
英文原文:Understand Functions in JavaScript
翻譯作者:碼農網 – 小峰
[ 轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]
相關文章
- 深入理解 JavaScript 回撥函式JavaScript函式
- 理解JavaScript中函式方法JavaScript函式
- 深入理解javascript系列(十六):深入高階函式JavaScript函式
- 深入理解javascript系列(十四):純函式JavaScript函式
- 深入理解Javascript中的隱式呼叫JavaScript
- 對JavaScript中函式物件的理解JavaScript函式物件
- 理解 JavaScript 中的高階函式JavaScript函式
- 深入認識javascript中的eval函式JavaScript函式
- TypeScript 中函式的理解?與 JavaScript 函式的區別?TypeScript函式JavaScript
- 深入理解javascript系列(十五):高階函式JavaScript函式
- 深入理解javascript函式系列第一篇——函式概述JavaScript函式
- 深入理解javascript系列(十七):函式柯里化JavaScript函式
- 深入理解 Go 中的 new() 和 make() 函式Go函式
- 理解javascript中的回撥函式(callback)【轉】JavaScript函式
- 深入理解javascript函式進階系列第四篇——惰性函式JavaScript函式
- 深入理解 Generator 函式函式
- 深入理解ES6中的箭頭函式函式
- 深入理解 JavaScript 中的 classJavaScript
- JavaScript函數語言程式設計之深入理解純函式JavaScript函數程式設計函式
- 理解JavaScript的函式呼叫和thisJavaScript函式
- javascript中的函式JavaScript函式
- 深入理解 函式、匿名函式、自執行匿名函式函式
- 深入理解JavaScript中的箭頭JavaScript
- 深入理解 JavaScript 中的 replace 方法JavaScript
- 深入探討JavaScript函式物件JavaScript函式物件
- JavaScript Function 函式深入總結JavaScriptFunction函式
- 深入理解JavaScript執行上下文、函式堆疊、提升的概念JavaScript函式
- 深入理解javascript原型和閉包(2)——函式和物件的關係JavaScript原型函式物件
- 深入理解javascript系列(十二):函式與函數語言程式設計(1)JavaScript函式函數程式設計
- 深入理解javascript系列(十三):函式與函數語言程式設計(2)JavaScript函式函數程式設計
- 深入理解函式節流與函式防抖函式
- 深入理解ES6 ---- 函式函式
- javascript中的原生函式JavaScript函式
- javascript中的trim函式JavaScript函式
- 深入理解JavaScript中的類繼承JavaScript繼承
- 深入理解JavaScript中的WeakMap和WeakSetJavaScript
- 深入理解JavaScript中的精度丟失JavaScript
- 深入理解箭頭函式和傳統函式的區別函式