<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>

          分享一篇阮老師關(guān)于ES6運算符擴(kuò)展,淺顯易懂!

          共 6915字,需瀏覽 14分鐘

           ·

          2021-07-14 14:39

          大家好,今天分享阮一峰老師的一篇類似的文章,里面的分析和代碼都很詳細(xì),希望對你有所幫助。

          目錄

          1. 指數(shù)運算符
          2. 鏈判斷運算符
          3. Null 判斷運算符
          4. 邏輯賦值運算符

          1.指數(shù)運算符

          ES2016 新增了一個指數(shù)運算符(**)。

          2 ** 2 // 4
          2 ** 3 // 8

          這個運算符的一個特點是右結(jié)合,而不是常見的左結(jié)合。多個指數(shù)運算符連用時,是從最右邊開始計算的。

          // 相當(dāng)于 2 ** (3 ** 2)
          2 ** 3 ** 2
          // 512

          上面代碼中,首先計算的是第二個指數(shù)運算符,而不是第一個。

          指數(shù)運算符可以與等號結(jié)合,形成一個新的賦值運算符(**=)。

          let a = 1.5;
          a **= 2;
          // 等同于 a = a * a;

          let b = 4;
          b **= 3;
          // 等同于 b = b * b * b;

          2.鏈判斷運算符

          編程實務(wù)中,如果讀取對象內(nèi)部的某個屬性,往往需要判斷一下,屬性的上層對象是否存在。比如,讀取message.body.user.firstName這個屬性,安全的寫法是寫成下面這樣。

          // 錯誤的寫法
          const  firstName = message.body.user.firstName || 'default';

          // 正確的寫法
          const firstName = (message
              && message.body
              && message.body.user
              && message.body.user.firstName) || 'default';

          上面例子中,firstName屬性在對象的第四層,所以需要判斷四次,每一層是否有值。

          三元運算符?:也常用于判斷對象是否存在。

          const fooInput = myForm.querySelector('input[name=foo]')
          const fooValue = fooInput ? fooInput.value : undefined

          上面例子中,必須先判斷fooInput是否存在,才能讀取fooInput.value

          這樣的層層判斷非常麻煩,因此 ES2020 引入了“鏈判斷運算符”(optional chaining operator)?.,簡化上面的寫法。

          const firstName = message?.body?.user?.firstName || 'default';
          const fooValue = myForm.querySelector('input[name=foo]')?.value

          上面代碼使用了?.運算符,直接在鏈?zhǔn)秸{(diào)用的時候判斷,左側(cè)的對象是否為nullundefined。如果是的,就不再往下運算,而是返回undefined

          下面是判斷對象方法是否存在,如果存在就立即執(zhí)行的例子。

          iterator.return?.()

          上面代碼中,iterator.return如果有定義,就會調(diào)用該方法,否則iterator.return直接返回undefined,不再執(zhí)行?.后面的部分。

          對于那些可能沒有實現(xiàn)的方法,這個運算符尤其有用。

          if (myForm.checkValidity?.() === false) {
              // 表單校驗失敗
              return;
          }

          上面代碼中,老式瀏覽器的表單對象可能沒有checkValidity()這個方法,這時?.運算符就會返回undefined,判斷語句就變成了undefined === false,所以就會跳過下面的代碼。

          鏈判斷運算符?.有三種寫法。

          • obj?.prop // 對象屬性是否存在
          • obj?.[expr] // 同上
          • func?.(...args) // 函數(shù)或?qū)ο蠓椒ㄊ欠翊嬖?/section>

          下面是obj?.[expr]用法的一個例子。

          let hex = "#C0FFEE".match(/#([A-Z]+)/i)?.[1];

          上面例子中,字符串的match()方法,如果沒有發(fā)現(xiàn)匹配會返回null,如果發(fā)現(xiàn)匹配會返回一個數(shù)組,?.運算符起到了判斷作用。

          下面是?.運算符常見形式,以及不使用該運算符時的等價形式。

          a?.b
          // 等同于
          a == null ? undefined : a.b

          a?.[x]
          // 等同于
          a == null ? undefined : a[x]

          a?.b()
          // 等同于
          a == null ? undefined : a.b()

          a?.()
          // 等同于
          a == null ? undefined : a()

          上面代碼中,特別注意后兩種形式,如果a?.b()a?.()。如果a?.b()里面的a.b有值,但不是函數(shù),不可調(diào)用,那么a?.b()是會報錯的。a?.()也是如此,如果a不是nullundefined,但也不是函數(shù),那么a?.()會報錯。

          使用這個運算符,有幾個注意點。

          (1)短路機(jī)制

          本質(zhì)上,?.運算符相當(dāng)于一種短路機(jī)制,只要不滿足條件,就不再往下執(zhí)行。

          a?.[++x]
          // 等同于
          a == null ? undefined : a[++x]

          上面代碼中,如果aundefinednull,那么x不會進(jìn)行遞增運算。也就是說,鏈判斷運算符一旦為真,右側(cè)的表達(dá)式就不再求值。

          (2)括號的影響

          如果屬性鏈有圓括號,鏈判斷運算符對圓括號外部沒有影響,只對圓括號內(nèi)部有影響。

          (a?.b).c
          // 等價于
          (a == null ? undefined : a.b).c

          上面代碼中,?.對圓括號外部沒有影響,不管a對象是否存在,圓括號后面的.c總是會執(zhí)行。

          一般來說,使用?.運算符的場合,不應(yīng)該使用圓括號。

          (3)報錯場合

          以下寫法是禁止的,會報錯。

          // 構(gòu)造函數(shù)
          new a?.()
          new a?.b()

          // 鏈判斷運算符的右側(cè)有模板字符串
          a?.`{b}`
          a?.b`{c}`

          // 鏈判斷運算符的左側(cè)是 super
          super?.()
          super?.foo

          // 鏈運算符用于賦值運算符左側(cè)
          a?.b = c

          (4)右側(cè)不得為十進(jìn)制數(shù)值

          為了保證兼容以前的代碼,允許foo?.3:0被解析成foo ? .3 : 0,因此規(guī)定如果?.后面緊跟一個十進(jìn)制數(shù)字,那么?.不再被看成是一個完整的運算符,而會按照三元運算符進(jìn)行處理,也就是說,那個小數(shù)點會歸屬于后面的十進(jìn)制數(shù)字,形成一個小數(shù)。

          3.Null 判斷運算符

          讀取對象屬性的時候,如果某個屬性的值是nullundefined,有時候需要為它們指定默認(rèn)值。常見做法是通過||運算符指定默認(rèn)值。

          const headerText = response.settings.headerText || 'Hello, world!';
          const animationDuration = response.settings.animationDuration || 300;
          const showSplashScreen = response.settings.showSplashScreen || true;

          上面的三行代碼都通過||運算符指定默認(rèn)值,但是這樣寫是錯的。開發(fā)者的原意是,只要屬性的值為nullundefined,默認(rèn)值就會生效,但是屬性的值如果為空字符串或false0,默認(rèn)值也會生效。

          為了避免這種情況,ES2020[1] 引入了一個新的 Null 判斷運算符??。它的行為類似||,但是只有運算符左側(cè)的值為nullundefined時,才會返回右側(cè)的值。

          const headerText = response.settings.headerText ?? 'Hello, world!';
          const animationDuration = response.settings.animationDuration ?? 300;
          const showSplashScreen = response.settings.showSplashScreen ?? true;

          上面代碼中,默認(rèn)值只有在左側(cè)屬性值為nullundefined時,才會生效。

          這個運算符的一個目的,就是跟鏈判斷運算符?.配合使用,為nullundefined的值設(shè)置默認(rèn)值。

          const animationDuration = response.settings?.animationDuration ?? 300;

          上面代碼中,如果response.settingsnullundefined,或者response.settings.animationDurationnullundefined,就會返回默認(rèn)值300。也就是說,這一行代碼包括了兩級屬性的判斷。

          這個運算符很適合判斷函數(shù)參數(shù)是否賦值。

          function Component(props) {
              const enable = props.enabled ?? true;
              // …
          }

          上面代碼判斷props參數(shù)的enabled屬性是否賦值,基本等同于下面的寫法。

          function Component(props) {
              const {
              enabled: enable = true,
              } = props;
              // …
          }

          ??本質(zhì)上是邏輯運算,它與其他兩個邏輯運算符&&||有一個優(yōu)先級問題,它們之間的優(yōu)先級到底孰高孰低。優(yōu)先級的不同,往往會導(dǎo)致邏輯運算的結(jié)果不同。

          現(xiàn)在的規(guī)則是,如果多個邏輯運算符一起使用,必須用括號表明優(yōu)先級,否則會報錯。

          // 報錯
          lhs && middle ?? rhs
          lhs ?? middle && rhs
          lhs || middle ?? rhs
          lhs ?? middle || rhs

          上面四個表達(dá)式都會報錯,必須加入表明優(yōu)先級的括號。

          (lhs && middle) ?? rhs;
          lhs && (middle ?? rhs);

          (lhs ?? middle) && rhs;
          lhs ?? (middle && rhs);

          (lhs || middle) ?? rhs;
          lhs || (middle ?? rhs);

          (lhs ?? middle) || rhs;
          lhs ?? (middle || rhs);

          4.邏輯賦值運算符

          ES2021 引入了三個新的邏輯賦值運算符[2](logical assignment operators),將邏輯運算符與賦值運算符進(jìn)行結(jié)合。

          // 或賦值運算符
          x ||= y
          // 等同于
          x || (x = y)

          // 與賦值運算符
          x &&= y
          // 等同于
          x && (x = y)

          // Null 賦值運算符
          x ??= y
          // 等同于
          x ?? (x = y)

          這三個運算符||=&&=??=相當(dāng)于先進(jìn)行邏輯運算,然后根據(jù)運算結(jié)果,再視情況進(jìn)行賦值運算。

          它們的一個用途是,為變量或?qū)傩栽O(shè)置默認(rèn)值。

          // 老的寫法
          user.id = user.id || 1;

          // 新的寫法
          user.id ||= 1;

          上面示例中,user.id屬性如果不存在,則設(shè)為1,新的寫法比老的寫法更緊湊一些。

          下面是另一個例子。

          function example(opts) {
              opts.foo = opts.foo ?? 'bar';
              opts.baz ?? (opts.baz = 'qux');
          }

          上面示例中,參數(shù)對象opts如果不存在屬性foo和屬性bar,則為這兩個屬性設(shè)置默認(rèn)值。有了“Null 賦值運算符”以后,就可以統(tǒng)一寫成下面這樣。

          function example(opts) {
              opts.foo ??= 'bar';
              opts.baz ??= 'qux';
          }```

          參考資料

          [1]

          ES2020: https://github.com/tc39/proposal-nullish-coalescing

          [2]

          邏輯賦值運算符: https://github.com/tc39/proposal-logical-assignment

          關(guān)于本文

          作者:阮一峰老師

          https://wangdoc.com/es6/operator.html


          瀏覽 24
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  园产一级a毛一级a看免费视频 | 成人做爰A片免费看网站 | 激情婷婷丁香五月 | 看免费操逼大片 | www.高清无码 |