JS 函數(shù)

在 JS 中吁恍,函數(shù)就是一個(gè)方法,一般都是為了實(shí)現(xiàn)某個(gè)功能。

1. 函數(shù)的作用和創(chuàng)建

var total = 10;
total += 10;
total = total/2;
total = total.toFixed(2); //=> 保留小數(shù)點(diǎn)后面兩位蹬挤,toFixed 時(shí)候數(shù)字包裝對(duì)象的方法缚窿,用來保留小數(shù)點(diǎn)后面的位數(shù)

在后續(xù)的代碼中,依然想實(shí)現(xiàn)相同的操作焰扳,就需要重新編寫代碼倦零。這樣的方式會(huì)導(dǎo)致頁面中存在大量冗余的代碼,也降低了開發(fā)效率吨悍。

函數(shù)的誕生的目的就是為了實(shí)現(xiàn)封裝:把實(shí)現(xiàn)一個(gè)功能的代碼封裝到一個(gè)函數(shù)中扫茅,以便后期重復(fù)利用。起到了低耦合高內(nèi)聚(減少頁面中的冗余代碼育瓜,提高代碼的重復(fù)利用率)的作用

創(chuàng)建函數(shù)

// ES5 中:
function 函數(shù)名([參數(shù)]) {
  // 函數(shù)體
}
// 表達(dá)式創(chuàng)建
var 函數(shù)名 = function ([參數(shù)]) {
  // 函數(shù)體
}

// ES6 箭頭函數(shù)
let 函數(shù)名或者說變量名 = ([參數(shù)]) => {
  // 函數(shù)體
}

2. 函數(shù)的創(chuàng)建執(zhí)行機(jī)制

函數(shù)作為引用類型葫隙,也是按照引用地址來操作的。

【創(chuàng)建函數(shù)】

  1. 首先開辟一個(gè)新的堆內(nèi)存躏仇,把函數(shù)體中的代碼當(dāng)作字符串存儲(chǔ)在內(nèi)存中(對(duì)象存儲(chǔ)的是鍵值對(duì))
  2. 在當(dāng)前上下文中聲明函數(shù)(變量)恋脚,函數(shù)聲明會(huì)提升到最前面
  3. 把開辟的堆內(nèi)存地址賦值給函數(shù)名(變量名)

此時(shí)輸出函數(shù)名 fn(不是 fn()),代表當(dāng)前函數(shù)本身焰手,如果我們要執(zhí)行函數(shù)糟描,就要加上小括號(hào)即 fn()。這是兩種不同本質(zhì)的操作书妻。

【函數(shù)執(zhí)行】
目的:把之前存儲(chǔ)到堆內(nèi)存中的代碼字符串變?yōu)檎嬲?JS 代碼自上而下執(zhí)行船响,從而實(shí)現(xiàn)應(yīng)有的功能。

  1. 函數(shù)執(zhí)行躲履,首先會(huì)形成一個(gè)私有的作用域(一個(gè)供代碼執(zhí)行的環(huán)境见间,也是一個(gè)棧內(nèi)存)
  2. 把之前在堆內(nèi)存中存儲(chǔ)的字符串復(fù)制一份到新開辟的棧內(nèi)存中變?yōu)檎嬲?JS 代碼
  3. 然后再進(jìn)行變量提升 (var function 提前聲明, 先形參賦值工猜, 再變量提升)
  4. 最后在這個(gè)新開辟的作用域中自上而下執(zhí)行

函數(shù)執(zhí)行的時(shí)候缤剧,都會(huì)形成一個(gè)全新的私有作用域(私有棧內(nèi)存),目的是:

  • 把原有堆內(nèi)存中存儲(chǔ)的字符串變成真正的 JS 代碼執(zhí)行
  • 保護(hù)里面的私有變量不受外界的干擾(和外界隔離)

我們把函數(shù)執(zhí)行的這種保護(hù)機(jī)制域慷,稱之為“閉包”

函數(shù)內(nèi)聲明的變量都是私有變量荒辕。

3. 函數(shù)中的參數(shù)

參數(shù)是函數(shù)的入口:當(dāng)我們在函數(shù)中封裝一個(gè)功能汗销,有一些不確定的因素,需要執(zhí)行函數(shù)的時(shí)候由用戶傳遞進(jìn)來抵窒。此時(shí)我們就基于參數(shù)的機(jī)制弛针,提供入口即可。

函數(shù)中的參數(shù)是按值傳遞的

//=> 此時(shí)的參數(shù)叫做形參(命名參數(shù)):入口李皇,形參是變量
function sum(n, m) {
  return n + m;
}

//=> 函數(shù)執(zhí)行時(shí)傳遞的值叫做實(shí)參:實(shí)參是具體的數(shù)據(jù)值削茁,即使寫的是變量或者表達(dá)式,也是把變量或者表達(dá)式計(jì)算的結(jié)果作為值傳遞給形參變量
sum(1, 2); //=> n:1, m:2
sum(1); //=> n:1, m:undefined
sum(); //=> n:undefined, m:undefined
sum(1, 2, 3) //=> n:1, m:2, 3 沒有形參變量接收

3.1 理解參數(shù)

JavaScript 中函數(shù)不介意傳遞多少個(gè)參數(shù)掉房,也不在乎傳進(jìn)去的參數(shù)是什么數(shù)據(jù)類型茧跋。即使定義時(shí),函數(shù)只有兩個(gè)形參卓囚,實(shí)際執(zhí)行的時(shí)候瘾杭,也可以傳遞任意個(gè)參數(shù)。

原因是 JavaScript 中的參數(shù)在內(nèi)部是用一個(gè)數(shù)組來表示的哪亿,函數(shù)接受到的始終是一個(gè)數(shù)組粥烁。

實(shí)際上,在函數(shù)內(nèi)部可以通過 arguments 對(duì)象來訪問這個(gè)參數(shù)數(shù)組蝇棉,從而獲取傳遞給函數(shù)的每一個(gè)參數(shù)讨阻。

3.2 arguments 對(duì)象

arguments 對(duì)象是一個(gè)類數(shù)組對(duì)象,可以通過索引訪問元素篡殷,也有 length 屬性訪問長度钝吮。是函數(shù)內(nèi)置的實(shí)參集合(內(nèi)置:函數(shù)天生就存在的機(jī)制,不管你是否設(shè)置形參板辽,是否傳遞實(shí)參搀绣,arguments 始終存在),只能在函數(shù)內(nèi)訪問戳气。

命名參數(shù)是有局限性的:我們需要具體知道用戶執(zhí)行的時(shí)候傳遞實(shí)參數(shù)量链患、順序等,才可以使用形參變量定義對(duì)應(yīng)入口瓶您。

通過 arguments 對(duì)象麻捻,函數(shù)不顯式的使用命名參數(shù),也能夠?qū)崿F(xiàn)一樣的功能呀袱。

function sum() {
  return arguments[0] + arguments[1];
}

因此在 JavaScript 中函數(shù)的一個(gè)重要特點(diǎn)是:命名參數(shù)只提供便利贸毕,但不是必須的。


length 屬性
可以通過其 length 屬性獲取傳入?yún)?shù)的個(gè)數(shù)夜赵,利用這一點(diǎn)讓函數(shù)能夠接受任意個(gè)參數(shù)并分別實(shí)現(xiàn)適當(dāng)?shù)墓δ堋?/p>

function add() {
  if (arguments.length == 1) {
    return arguments[0] + 10;
  } else if (arguments.length == 2) {
    return arguments[0] + arguments[1];
  }
  ...
}

arguments 同樣可以和命名參數(shù)一起使用明棍。


arguments 的映射機(jī)制

arguments 中的值會(huì)與對(duì)應(yīng)命名參數(shù)(形參)的值保持同步

function add(n, m) {
  arguments[1] = 10;
  return n + m;
}
add(1,2) //=> 11
// 反過來改變命名參數(shù)的值也是一樣,同步改變

arguments 對(duì)象和形參之間的映射是在函數(shù)執(zhí)行后形參賦值的一瞬間寇僧,瀏覽器通過 arguments 中的索引來完成和對(duì)應(yīng)形參變量中的映射機(jī)制搭建摊腋。一開始沒有建立起來的沸版,即使在后面改變 arguments 對(duì)象,也無法形成映射兴蒸。

如果形參比 arguments 中個(gè)數(shù)多视粮,那么多出來的形參是無法和 arguments 中對(duì)應(yīng)的索引建立關(guān)聯(lián)的。

function fn(x, y) {
  /* 形參賦值:x = 10, y = undefined
   * 
   * argumenrs
   *  0: 10
   *  length: 1
   */
  var arg = arguments;
  arg[0] = 100;
  console.log(x); //=> 100橙凳,存在索引蕾殴,形成映射
  
  y = 200;
  console.log(arg[1]); //=> undefined

  //=> 后面再改變 arguments,也無法形成映射
  arg[1] = 150;
  console.log(y); //=> 200
}
fn(10);

注意:

  1. 這并不說明兩個(gè)值訪問相同的內(nèi)存空間岛啸,它們的內(nèi)存空間是相互獨(dú)立的钓觉,只是值會(huì)保持同步
  2. arguments 對(duì)象的長度由傳入的參數(shù)個(gè)數(shù)決定,不是由定義函數(shù)時(shí)的命名參數(shù)個(gè)數(shù)決定
  3. 沒有傳遞值的命名參數(shù)將被自動(dòng)賦值為 undefined
  4. 嚴(yán)格模式下坚踩,不允許改變 arguments 對(duì)象荡灾,同時(shí)與命名參數(shù)不同步

callee 屬性
存儲(chǔ)的是當(dāng)前函數(shù)本身。嚴(yán)格模式下堕虹,訪問會(huì)報(bào)錯(cuò)。


callee.caller 屬性
存儲(chǔ)的是調(diào)用函數(shù)的環(huán)境芬首。全局調(diào)用的話赴捞,值為 null。嚴(yán)格模式下郁稍,訪問會(huì)報(bào)錯(cuò)赦政。


應(yīng)用
任意數(shù)求和:不管函數(shù)執(zhí)行的時(shí)候,傳遞多少實(shí)參值進(jìn)來耀怜,我們都可以求和

function sum() {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

優(yōu)化:在累加時(shí)恢着,把字符串轉(zhuǎn)換為數(shù)字,對(duì)于非有效數(shù)字财破,不再相加掰派。

function sum() {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    var item = Number(arguments[i]);
    isNaN(item) ? null : total += item;
  }
  return total;
}

//=> ES6
var sum = (...arg) => eval(arg.filter(item => !isNaN(item)).join('+'));

4. 返回值

返回值是函數(shù)的出口,把函數(shù)運(yùn)行的結(jié)果或者函數(shù)體中的部分信息拿到函數(shù)外面去使用左痢。

函數(shù)在任何時(shí)候都可以通過 return 返回一個(gè)值靡羡,返回之后,函數(shù)停止并立即退出俊性,后面代碼不再執(zhí)行略步。

function fn(n, m) {
  var total = 0;
  total = n + m;
  return total;
  //=> 并不是把 total 變量返回,返回的是變量存儲(chǔ)的值定页,return 返回的永遠(yuǎn)是一個(gè)值
}
fn(1,2) //=> 3

要么讓函數(shù)始終返回一個(gè)值趟薄,要么始終不會(huì)返回值。

5. 匿名函數(shù)

匿名函數(shù):沒有函數(shù)名的函數(shù)

  • 函數(shù)表達(dá)式:把函數(shù)當(dāng)作值賦值給變量或者元素的事件
  • 自執(zhí)行函數(shù):創(chuàng)建和執(zhí)行一起完成(立即執(zhí)行匿名函數(shù))
  • 回調(diào)函數(shù):將匿名函數(shù)當(dāng)作參數(shù)傳入函數(shù)中
//=> 函數(shù)表達(dá)式
var sum = function() {

};

//=> 自執(zhí)行函數(shù)
(function(){

})();
~function() {

}();
+function() {

}();
!function() {

}();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末典徊,一起剝皮案震驚了整個(gè)濱河市杭煎,隨后出現(xiàn)的幾起案子恩够,更是在濱河造成了極大的恐慌,老刑警劉巖岔帽,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玫鸟,死亡現(xiàn)場離奇詭異,居然都是意外死亡犀勒,警方通過查閱死者的電腦和手機(jī)屎飘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贾费,“玉大人钦购,你說我怎么就攤上這事」酉簦” “怎么了押桃?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長导犹。 經(jīng)常有香客問我唱凯,道長,這世上最難降的妖魔是什么谎痢? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任磕昼,我火速辦了婚禮,結(jié)果婚禮上节猿,老公的妹妹穿的比我還像新娘票从。我一直安慰自己,他們只是感情好滨嘱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布峰鄙。 她就那樣靜靜地躺著,像睡著了一般太雨。 火紅的嫁衣襯著肌膚如雪吟榴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天囊扳,我揣著相機(jī)與錄音煤墙,去河邊找鬼。 笑死宪拥,一個(gè)胖子當(dāng)著我的面吹牛仿野,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播她君,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼脚作,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起球涛,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤劣针,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后亿扁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺典,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年从祝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了襟己。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牍陌,死狀恐怖擎浴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毒涧,我是刑警寧澤贮预,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站契讲,受9級(jí)特大地震影響仿吞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捡偏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一唤冈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霹琼,春花似錦务傲、人聲如沸凉当。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽看杭。三九已至忠藤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楼雹,已是汗流浹背模孩。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贮缅,地道東北人榨咐。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像谴供,于是被迫代替她去往敵國和親块茁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)是一段可以反復(fù)調(diào)用的代碼塊。函數(shù)還能接受輸入的參數(shù)数焊,不同的參數(shù)會(huì)返回不同的值永淌。 概述 函數(shù)的聲明 JavaSc...
    oWSQo閱讀 1,249評(píng)論 0 4
  • 在js中,函數(shù)本身屬于對(duì)象的一種佩耳,因此可以定義遂蛀、賦值,作為對(duì)象的屬性或者成為其他函數(shù)的參數(shù)干厚。函數(shù)名只是函數(shù)這個(gè)對(duì)象...
    bjhu電net閱讀 527評(píng)論 0 5
  • 1. 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*) 函數(shù)在JS中有三種方式來定義:函數(shù)聲明(function decla...
    進(jìn)擊的阿群閱讀 439評(píng)論 0 1
  • 今天我和爸爸一起做手工了李滴,有藍(lán)天、白云萍诱、房子悬嗓、鵝、還有小河裕坊,爸爸做的藍(lán)天包竹,和白云,我做的小河籍凝、大白鵝周瞎、還有房子,我...
    一班楊特閱讀 127評(píng)論 0 0
  • 傳說饵蒂,在天地之外声诸,有一座神秘的仙山,常年彌漫著濃霧退盯,每到七夕之時(shí)彼乌,仙山上的濃霧就會(huì)慢慢退去,周圍所有的飛禽走...
    竹鴻初閱讀 705評(píng)論 0 1