摘要:中函數是一等公民。小明小明調用函數時,傳遞給函數的值被稱為函數的實參值傳遞,對應位置的函數參數名叫作形參。所以不推薦使用構造函數創建函數因為它需要的函數體作為字符串可能會阻止一些引擎優化也會引起瀏覽器資源回收等問題。
函數
之前幾節中圍繞著函數梳理了 this、原型鏈、作用域鏈、閉包等內容,這一節梳理一下函數本身的一些特點。
javascript 中函數是一等公民。 并且函數也是對象,因為它們可以像任何其他對象一樣具有屬性和方法。它們與其他對象的區別在于函數可以被調用。簡而言之,它們是 Function 對象。
一個函數是可以通過外部代碼調用的一個“子程序”,函數內部包含了執行語句或表達式。每個自定義函數都是Function的實例,并繼承Function的所有屬性和方法,而Function 是語言本身提供的編程接口。
function foo (name) { console.log(`hello, ${name}`) } var res = foo(`小明`) // "hello, 小明" console.log(res)
調用函數時,傳遞給函數的值被稱為函數的實參(值傳遞),對應位置的函數參數名叫作形參。如果實參是一個包含原始值(數字,字符串,布爾值)的變量,則就算函數在內部改變了對應形參的值,返回后,該實參變量的值也不會改變。如果實參是一個對象引用,則對應形參會和該實參指向同一個對象。假如函數在內部改變了對應形參的值,返回后,實參指向的對象的值也會改.(歡迎查看參數傳值一節)
如果函數內部沒有通過return返回一個值,則函數會默認返回undefined.
函數在實際開發中承擔著代碼分塊、 功能封裝等任務。
函數定義// 函數申明 foo() let a = 1 function foo () { console.log(a) } // 函數表達式 (函數變量) let too = function (){ console.log("hello") } too() // Function 構造函數實例化一個函數 let bar = new Function("console.log("hello")") bar() // 箭頭函數 let fns = () => { console.log("hello") } fns()
需要注意的是函數申明和函數表達式在變量提升時的區別,強烈建議閱讀變量對象相關內容:詳情。同時函數申明的函數名稱不能被改變,而函數表達式賦值給的變量可以被重新賦值。
函數的各種定義方式就不深入,這里需要注意的是通過使用構造函數(new Function())方式創建的函數,在每次調用的時候都會解析一次。所以不推薦使用 Function 構造函數創建函數, 因為它需要的函數體作為字符串可能會阻止一些 JS 引擎優化,也會引起瀏覽器資源回收等問題。
argumentsarguments同this一樣是函數提供給函數內部使用的一個屬性(ES6中箭頭函數沒有)。通過arguments我們可以獲取調用函數時傳遞進來的實參, 該屬性是一個類數組對象,我們可以像數組一樣進行數值的讀取。
function foo () { let a = arguments[0] // 獲取函數的第一個參數 let b = arguments[1] // 獲取函數的第二個餐宿 // 遍歷函數的所有參數 for (let arg in arguments) { console.log(`${arg}: ${arguments[arg]}`) } arguments[2] = 1122 } foo(1, 2, 3)
雖然arguments是類似于數組,但是除了通過索引獲取元素和length屬性外,不能使用push、pop等方法。如果確實要進行修改操作,可以將其轉換為真正的數組:
let args = Array.prototype.slice.call(arguments) let args = [].slice.call(arguments) // ES2015 let args = Array.from(arguments)自執行函數
把函數定義和函數執行結合到一起就是立即執行函數,也叫自執行函數。
在官方術語中叫做 IIFE( 立即調用函數表達式),是在定義時就會立即執行的函數。被稱為自執行匿名函數的設計模式,主要包括兩部分:
第一部分是包圍在 圓括號運算符() 里的一個匿名函數,這個匿名函數擁有獨立的詞法作用域。這不僅避免了外界訪問此 IIFE 中的變量,而且又不會污染全局作用域。借用這個特性我們可以對局部功能進行封裝,只暴露很少的方法給外部環境,這也是很多第三方庫的封裝方法之一。
第二部分再一次使用 () 創建了一個立即執行函數表達式,JavaScript 引擎到此將直接執行函數。
當函數變成立即執行的函數表達式時,表達式中的變量不能從外部訪問:
(function () { var a = 1 })() console.log(a) // a is not defined
將 IIFE 分配給一個變量,不是存儲 IIFE 本身,而是存儲 IIFE 執行后返回的結果:
let bar = (function (){ let a = 123 return a })() console.log(bar) // 123
別外自執行函數還有一些其他使用方式:
// 下面2個括弧()都會立即執行 (function(){ /* code */ }()); (function(){ /* code */ })(); // 由于括弧()和JS的&&,異或,逗號等操作符是在函數表達式和函數聲明上消除歧義的 // 所以一旦解析器知道其中一個已經是表達式了,其它的也都默認為表達式了 var i = function(){ /* code */ }(); true && function(){ /* code */ }(); 0, function(){ /* code */ }(); // 如果你不在意返回值,或者不怕難以閱讀 // 你甚至可以在function前面加一元操作符號 !function(){ /* code */ }(); ~function(){ /* code */ }(); -function(){ /* code */ }(); +function(){ /* code */ }(); // 上面這種使用一元表達式這種方式其實是不太常見的 // 而且有時候肯定在一些場景下存在一些弊端,因為一元表達式會有一個不為undefined的返回值 // 要想返回值為undefined,那么最保險的就是使用void關鍵字 void function(){/* code */}();
()左邊必須是一個函數表達式,而不是一個函數申明。自執行函數也會用在模塊封裝的場景下。
閉包函數和函數聲明時的詞法作用域形成閉包。我們可以使用閉包來保存變量、封裝不需要暴露的私有屬性和方法。
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } var foo = checkscope(); foo(); // "local scope"
徹底理解閉包的最好途徑就是理解閉包的由來,閉包的產生和作用域鏈有密切關系。在作用域鏈一節已經梳理過閉包的原理。
函數式編程未完成
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107968.html
摘要:構造函數和實例都通過屬性指向了原形。代碼示例是構造函數的實例的屬性與的屬性保存的值相等,即他們指向同一個對象原形。 講清楚之javascript原型 標簽: javascript javascript 中原形是一個比較難于理解的概念。javascript 權威指南在原形這一章也花了大量的篇幅進行介紹,也許你已經讀過javascript 權威指南,或者已經是讀第N篇了,然而這篇文章的目...
摘要:講清楚之參數傳值參數傳值是指函數調用時,給函數傳遞配置或運行參數的行為,包括通過進行傳值。所以對的賦值會改變上下文棧中標識符保存的具體值此時如果使用的是按引用傳遞,則變量所指向的對象因該也被賦值為。 講清楚之 javascript 參數傳值 參數傳值是指函數調用時,給函數傳遞配置或運行參數的行為,包括通過call、apply 進行傳值。 在實際開發中,我們總結javascript參數傳...
閱讀 1876·2021-09-24 09:48
閱讀 3220·2021-08-26 14:14
閱讀 1674·2021-08-20 09:36
閱讀 1461·2019-08-30 15:55
閱讀 3628·2019-08-26 17:15
閱讀 1425·2019-08-26 12:09
閱讀 607·2019-08-26 11:59
閱讀 3323·2019-08-26 11:57