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