<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ES6 進(jìn)階:你不知道的 Rest 參數(shù)與 Spread 語法細(xì)節(jié)

          共 5340字,需瀏覽 11分鐘

           ·

          2021-10-10 19:14

          Rest 參數(shù)與 Spread 語法

          在 JavaScript 中,很多內(nèi)建函數(shù)都支持傳入任意數(shù)量的參數(shù)。

          例如:

          • Math.max(arg1, arg2, ..., argN) —— 返回入?yún)⒅械淖畲笾怠?/section>
          • Object.assign(dest, src1, ..., srcN) —— 依次將屬性從 src1..N 復(fù)制到 dest
          • ……等。

          在本文中,我們將學(xué)習(xí)如何編程實(shí)現(xiàn)支持函數(shù)可傳入任意數(shù)量的參數(shù)。以及,如何將數(shù)組作為參數(shù)傳遞給這類函數(shù)。

          Rest 參數(shù) ...

          在 JavaScript 中,無論函數(shù)是如何定義的,你都可以使用任意數(shù)量的參數(shù)調(diào)用函數(shù)。

          例如:

          function?sum(a,?b)?{
          ??return?a?+?b;
          }

          alert(?sum(1,?2,?3,?4,?5)?);

          雖然這里不會(huì)因?yàn)閭魅搿斑^多”的參數(shù)而報(bào)錯(cuò)。但是當(dāng)然,在結(jié)果中只有前兩個(gè)參數(shù)被計(jì)算進(jìn)去了。

          Rest 參數(shù)可以通過使用三個(gè)點(diǎn) ... 并在后面跟著包含剩余參數(shù)的數(shù)組名稱,來將它們包含在函數(shù)定義中。這些點(diǎn)的字面意思是“將剩余參數(shù)收集到一個(gè)數(shù)組中”。

          例如,我們需要把所有的參數(shù)都放到數(shù)組 args 中:

          function?sumAll(...args)?{?//?數(shù)組名為?args
          ??let?sum?=?0;

          ??for?(let?arg?of?args)?sum?+=?arg;

          ??return?sum;
          }

          alert(?sumAll(1)?);?//?1
          alert(?sumAll(1,?2)?);?//?3
          alert(?sumAll(1,?2,?3)?);?//?6

          我們也可以選擇獲取第一個(gè)參數(shù)作為變量,并將剩余的參數(shù)收集起來。

          下面的例子把前兩個(gè)參數(shù)定義為變量,并把剩余的參數(shù)收集到 titles 數(shù)組中:

          function?showName(firstName,?lastName,?...titles)?{
          ??alert(?firstName?+?'?'?+?lastName?);?//?Julius?Caesar

          ??//?剩余的參數(shù)被放入?titles?數(shù)組中
          ??//?i.e.?titles?=?["Consul",?"Imperator"]
          ??alert(?titles[0]?);?//?Consul
          ??alert(?titles[1]?);?//?Imperator
          ??alert(?titles.length?);?//?2
          }

          showName("Julius",?"Caesar",?"Consul",?"Imperator");

          Rest 參數(shù)必須放到參數(shù)列表的末尾

          Rest 參數(shù)會(huì)收集剩余的所有參數(shù),因此下面這種用法沒有意義,并且會(huì)導(dǎo)致錯(cuò)誤:

          function?f(arg1,?...rest,?arg2)?{?// arg2 在 ...rest 后面?!
          ??//?error
          }

          ...rest 必須處在最后。

          "arguments" 變量

          有一個(gè)名為 arguments 的特殊的類數(shù)組對象,該對象按參數(shù)索引包含所有參數(shù)。

          例如:

          function?showName()?{
          ??alert(?arguments.length?);
          ??alert(?arguments[0]?);
          ??alert(?arguments[1]?);

          ??//?它是可遍歷的
          ??//?for(let?arg?of?arguments)?alert(arg);
          }

          //?依次顯示:2,Julius,Caesar
          showName("Julius",?"Caesar");

          //?依次顯示:1,Ilya,undefined(沒有第二個(gè)參數(shù))
          showName("Ilya");

          在過去,JavaScript 中沒有 rest 參數(shù),而使用 arguments 是獲取函數(shù)所有參數(shù)的唯一方法。現(xiàn)在它仍然有效,我們可以在一些老代碼里找到它。

          但缺點(diǎn)是,盡管 arguments 是一個(gè)類數(shù)組,也是可迭代對象,但它終究不是數(shù)組。它不支持?jǐn)?shù)組方法,因此我們不能調(diào)用 arguments.map(...) 等方法。

          此外,它始終包含所有參數(shù),我們不能像使用 rest 參數(shù)那樣只截取入?yún)⒌囊徊糠帧?/p>

          因此,當(dāng)我們需要這些功能時(shí),最好使用 rest 參數(shù)。

          箭頭函數(shù)是沒有 "arguments"

          如果我們在箭頭函數(shù)中訪問 arguments,訪問到的 arguments 并不屬于箭頭函數(shù),而是屬于箭頭函數(shù)外部的“普通”函數(shù)。

          舉個(gè)例子:

          function?f()?{
          ??let?showArg?=?()?=>?alert(arguments[0]);
          ??showArg();
          }

          f(1);?//?1

          我們已經(jīng)知道,箭頭函數(shù)沒有自身的?`this`?,F(xiàn)在我們知道了它們也沒有特殊的?`arguments`?對象。

          Spread 語法

          我們剛剛看到了如何從參數(shù)列表中獲取數(shù)組。

          不過有時(shí)候我們也需要做與之相反的事兒。

          例如,內(nèi)建函數(shù) Math.max[1] 會(huì)返回參數(shù)中最大的值:

          alert(?Math.max(3,?5,?1)?);?//?5

          假如我們有一個(gè)數(shù)組 [3, 5, 1],我們該如何用它調(diào)用 Math.max 呢?

          直接把數(shù)組“原樣”傳入是不會(huì)奏效的,因?yàn)?Math.max 希望你傳入一個(gè)列表形式的數(shù)值型參數(shù),而不是一個(gè)數(shù)組:

          let?arr?=?[3,?5,?1];

          alert(?Math.max(arr)?);?//?NaN

          毫無疑問,我們不可能手動(dòng)地去一一設(shè)置參數(shù) Math.max(arg[0], arg[1], arg[2]),因?yàn)槲覀儾淮_定這兒有多少個(gè)。在腳本執(zhí)行時(shí),可能參數(shù)數(shù)組中有很多個(gè)元素,也可能一個(gè)都沒有。并且這樣設(shè)置的代碼也很丑。

          Spread 語法 來幫助你了!它看起來和 rest 參數(shù)很像,也使用 ...,但是二者的用途完全相反。

          當(dāng)在函數(shù)調(diào)用中使用 ...arr 時(shí),它會(huì)把可迭代對象 arr “展開”到參數(shù)列表中。

          Math.max 為例:

          let?arr?=?[3,?5,?1];

          alert(?Math.max(...arr)?);?//?5(spread?語法把數(shù)組轉(zhuǎn)換為參數(shù)列表)

          我們還可以通過這種方式傳遞多個(gè)可迭代對象:

          let?arr1?=?[1,?-2,?3,?4];
          let?arr2?=?[8,?3,?-8,?1];

          alert(?Math.max(...arr1,?...arr2)?);?//?8

          我們甚至還可以將 spread 語法與常規(guī)值結(jié)合使用:

          let?arr1?=?[1,?-2,?3,?4];
          let?arr2?=?[8,?3,?-8,?1];

          alert(?Math.max(1,?...arr1,?2,?...arr2,?25)?);?//?25

          并且,我們還可以使用 spread 語法來合并數(shù)組:

          let?arr?=?[3,?5,?1];
          let?arr2?=?[8,?9,?15];

          let?merged?=?[0,?...arr,?2,?...arr2];

          alert(merged);?//?0,3,5,1,2,8,9,15(0,然后是?arr,然后是?2,然后是?arr2)

          在上面的示例中,我們使用數(shù)組展示了 spread 語法,其實(shí)任何可迭代對象都可以。

          例如,在這兒我們使用 spread 語法將字符串轉(zhuǎn)換為字符數(shù)組:

          let?str?=?"Hello";

          alert(?[...str]?);?//?H,e,l,l,o

          Spread 語法內(nèi)部使用了迭代器來收集元素,與 for..of 的方式相同。

          因此,對于一個(gè)字符串,for..of 會(huì)逐個(gè)返回該字符串中的字符,...str 也同理會(huì)得到 "H","e","l","l","o" 這樣的結(jié)果。隨后,字符列表被傳遞給數(shù)組初始化器 [...str]。

          對于這個(gè)特定任務(wù),我們還可以使用 Array.from 來實(shí)現(xiàn),因?yàn)樵摲椒〞?huì)將一個(gè)可迭代對象(如字符串)轉(zhuǎn)換為數(shù)組:

          let?str?=?"Hello";

          //?Array.from?將可迭代對象轉(zhuǎn)換為數(shù)組
          alert(?Array.from(str)?);?//?H,e,l,l,o

          運(yùn)行結(jié)果與 [...str] 相同。

          不過 Array.from(obj)[...obj] 存在一個(gè)細(xì)微的差別:

          • Array.from 適用于類數(shù)組對象也適用于可迭代對象。
          • Spread 語法只適用于可迭代對象。

          因此,對于將一些“東西”轉(zhuǎn)換為數(shù)組的任務(wù),Array.from 往往更通用。

          獲取一個(gè) array/object 的副本

          還記得我們 之前講過的[2] Object.assign() 嗎?

          使用 spread 語法也可以做同樣的事情。

          let?arr?=?[1,?2,?3];
          let?arrCopy?=?[...arr];?//?將數(shù)組?spread?到參數(shù)列表中
          ????????????????????????//?然后將結(jié)果放到一個(gè)新數(shù)組

          //?兩個(gè)數(shù)組中的內(nèi)容相同嗎?
          alert(JSON.stringify(arr)?===?JSON.stringify(arrCopy));?//?true

          //?兩個(gè)數(shù)組相等嗎?
          alert(arr?===?arrCopy);?//?false(它們的引用是不同的)

          //?修改我們初始的數(shù)組不會(huì)修改副本:
          arr.push(4);
          alert(arr);?//?1,?2,?3,?4
          alert(arrCopy);?//?1,?2,?3

          并且,也可以通過相同的方式來復(fù)制一個(gè)對象:

          let?obj?=?{?a:?1,?b:?2,?c:?3?};
          let?objCopy?=?{?...obj?};?//?將對象?spread?到參數(shù)列表中
          ??????????????????????????//?然后將結(jié)果返回到一個(gè)新對象

          //?兩個(gè)對象中的內(nèi)容相同嗎?
          alert(JSON.stringify(obj)?===?JSON.stringify(objCopy));?//?true

          //?兩個(gè)對象相等嗎?
          alert(obj?===?objCopy);?//?false?(not?same?reference)

          //?修改我們初始的對象不會(huì)修改副本:
          obj.d?=?4;
          alert(JSON.stringify(obj));?//?{"a":1,"b":2,"c":3,"d":4}
          alert(JSON.stringify(objCopy));?//?{"a":1,"b":2,"c":3}

          這種方式比使用 let arrCopy = Object.assign([], arr); 來復(fù)制數(shù)組,或使用 let objCopy = Object.assign({}, obj); 來復(fù)制對象寫起來要短得多。因此,只要情況允許,我們更喜歡使用它。

          總結(jié)

          當(dāng)我們在代碼中看到 "..." 時(shí),它要么是 rest 參數(shù),要么就是 spread 語法。

          有一個(gè)簡單的方法可以區(qū)分它們:

          • ... 出現(xiàn)在函數(shù)參數(shù)列表的最后,那么它就是 rest 參數(shù),它會(huì)把參數(shù)列表中剩余的參數(shù)收集到一個(gè)數(shù)組中。
          • ... 出現(xiàn)在函數(shù)調(diào)用或類似的表達(dá)式中,那它就是 spread 語法,它會(huì)把一個(gè)數(shù)組展開為列表。

          使用場景:

          • Rest 參數(shù)用于創(chuàng)建可接受任意數(shù)量參數(shù)的函數(shù)。
          • Spread 語法用于將數(shù)組傳遞給通常需要含有許多參數(shù)的列表的函數(shù)。

          它們倆的出現(xiàn)幫助我們輕松地在列表和參數(shù)數(shù)組之間來回轉(zhuǎn)換。

          “舊式”的 arguments(類數(shù)組且可迭代的對象)也依然能夠幫助我們獲取函數(shù)調(diào)用中的所有參數(shù)。


          現(xiàn)代 JavaScript 教程:開源的現(xiàn)代 JavaScript 從入門到進(jìn)階的優(yōu)質(zhì)教程。React 官方文檔推薦,與 MDN 并列的 JavaScript 學(xué)習(xí)教程[3]。

          在線免費(fèi)閱讀:https://zh.javascript.info


          參考資料

          [1]

          Math.max: https://developer.mozilla.org/zh/docs/Web/JavaScript/Reference/Global_Objects/Math/max

          [2]

          之前講過的: https://zh.javascript.info/object-copy#ke-long-yu-he-bing-objectassign

          [3]

          React 官方文檔推薦,與 MDN 并列的 JavaScript 學(xué)習(xí)教程: https://zh-hans.reactjs.org/docs/getting-started.html#javascript-resources

          看完三件事

          如果你覺得本文對你有幫助,我想請你幫個(gè)忙:

          1. 轉(zhuǎn)發(fā)本文,點(diǎn)贊或者點(diǎn)個(gè)「在看」,是對我最大的認(rèn)可和支持;
          2. 關(guān)注公眾號(hào)「全棧修煉」,訂閱更多精彩內(nèi)容,獲取更多學(xué)習(xí)資料;



          ?

          瀏覽 70
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩毛片在线免费观看 | 91社成人影院 | 中国免费av | 一级内射毛片 | 东京热一区二区三区四区 |