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

          你應該了解的 23 個超實用 JS 技巧

          共 18437字,需瀏覽 37分鐘

           ·

          2021-09-28 00:14

          作者:望道(已獲轉載授權)

          原文:https://juejin.cn/post/6955293673365962789

          本文的目的在于幫助大家更加熟練的運用 JavaScript 語言來進行開發(fā)工作。

          帶有多個條件的 if 語句

          把多個值放在一個數(shù)組中,然后調用數(shù)組的 includes 方法。

          // bad ??
          if (x === "abc" || x === "def" || x === "ghi" || x === "jkl") {
            //logic
          }

          // better ??
          if (["abc""def""ghi""jkl"].includes(x)) {
            //logic
          }

          使用條件表達式簡化 if true...else

          // bad ??
          let test: boolean;
          if (x > 100) {
            test = true;
          else {
            test = false;
          }

          // better ??
          let test = x > 10 ? true : false;
          //或者這樣
          let test = x > 10;

          console.log(test);

          假值(undefined、null、0、false、NaN、空字符串)檢查

          當我們創(chuàng)建了新變量,有時候想要檢查引用的變量是不是nullundefined空字符串 等假值。JavaScript 確實有一個很好的快捷方式來實現(xiàn)這種檢查-邏輯或操作符(||)

          ||會在左側操作數(shù)為假值時返回右側操作數(shù)

          只有當左側為:

          • 空字符串: ''``
          • NaN
          • 0
          • null
          • undefined
          • false

          邏輯或操作符(||) 會返回有右側的值

          // bad ??
          if (test1 !== null || test1 !== undefined || test1 !== "") {
            let test2 = test1;
          }

          // better ??
          let test2 = test1 || "";

          // bad ??
          if (test1 === true) or if (test1 !== "") or if (test1 !== null)

          // better ??
          if (test1){
            // do some
          }else{
            // do other
          }

          注意:如果 test1 有值,將執(zhí)行 if 之后的邏輯,這個操作符主要用于 null,undefinded,空字符串 檢查。

          使用空值合并操作符-??

          只有當左側為

          • null
          • undefined

          空值合并操作符(??) 會返回右側的值

          const baz = 0 ?? 42;
          console.log(baz);
          // expected output: 0

          注意:與邏輯或操作符(||)不同,||會在左側操作數(shù)為假值時返回右側操作數(shù)

          只有當左側為:

          • 空字符串: ''``
          • NaN
          • 0
          • null
          • undefined

          邏輯或操作符(||) 會返回有右側的值

          var a = "" || 1;
          // 輸出 1
          console.log(a);

          null 檢查和默認賦值

          let test1 = null;
          let test2 = test1 ?? "";

          console.log("null check", test2); // 輸出空字符串 ""

          undefined 檢查和默認賦值

          const test = undefined ?? "default";

          console.log(test);
          // expected output: "default"

          比較后返回

          // bad ??
          let test;
          function checkReturn({
            if (!(test === undefined)) {
              return test;
            } else {
              return callMe("test");
            }
          }

          // better ??
          function checkReturn({
            return test ?? callMe("test");
          }

          使用可選鏈操作符-?.

          ?. 也叫鏈判斷運算符。它允許開發(fā)人員讀取深度嵌套在對象鏈中的屬性值,而不必驗證每個引用。當引用為空時,表達式停止計算并返回 undefined

          const travelPlans = {
            destination: "DC",
            monday: {
              location: "National Mall",
              budget: 200,
            },
          };

          // bad ??
          const res =
            travelPlans &&
            travelPlans.tuesday &&
            travelPlans.tuesday.location &&
            travelPlans.tuesday.location.href;

          // better ??
          // 輸出 undefined
          const res1 = travelPlans?.tuesday?.location?.href;

          用于多個條件判斷的 && 操作符

          如果只在變量為 true 時才調用函數(shù),可以使用 && 操作符

          // bad ??
          if (test1) {
            callMethod();
          }

          // better ??
          test1 && callMethod();

          當你在 React 中想要有條件地渲染某個組件時,這個與 (&&)短路寫法比較有用。例如:

          <div> {this.state.isLoading && <Loading />} </div>

          switch 簡化

          我們可以將條件保存在鍵值對象中,并根據(jù)條件來調用它們。

          // bad ??
          switch (data) {
            case 1:
              test1();
              break;
            case 2:
              test2();
              break;
            case 3:
              test();
              break;
            // And so on...
          }

          // better ??
          var data = {
            1: test1,
            2: test2,
            3: test,
          };

          // 如果type 在 data中存在, 則執(zhí)行對應的函數(shù)
          data[type] && data[type]();

          默認參數(shù)值

          // bad ??
          function add(test1, test2{
            if (test1 === undefined) test1 = 1;
            if (test2 === undefined) test2 = 2;
            return test1 + test2;
          }

          // better ??
          add = (test1 = 1, test2 = 2) => test1 + test2;
          add(); //output: 3

          條件查找簡化

          如果我們要基于不同的類型調用不同的方法,可以使用多個 else if 語句或 switch,但有沒有比這更好的簡化技巧呢?其實是前面的 switch 簡化方式一樣!

          // bad ??
          if (type === "test1") {
            test1();
          else if (type === "test2") {
            test2();
          else if (type === "test3") {
            test3();
          else if (type === "test4") {
            test4();
          else {
            throw new Error("Invalid value " + type);
          }

          // better ??
          var types = {
            test1,
            test2,
            test3,
            test4,
          };
          types[type] && types[type]();

          對象屬性賦值

          let test1 = "a";
          let test2 = "b";

          // bad ??
          let obj = { test1: test1, test2: test2 };

          // better ??
          let obj = { test1, test2 };

          解構賦值

          // bad ??
          const test1 = this.data.test1;
          const test2 = this.data.test2;
          const test2 = this.data.test3;

          // better ??
          const { test1, test2, test3 } = this.data;

          模板字符串

          如果你厭倦了使用 + 將多個變量連接成一個字符串,那么這個簡化技巧將讓你不再頭痛。

          // bad ??
          const welcome = "Hi " + test1 + " " + test2 + ".";
          // better ??
          const welcome = `Hi ${test1} ${test2}`;

          跨行字符串

          // bad ??
          const data =
            "abc abc abc abc abc abc\n\t" + "test test,test test test test\n\t";
          // better ??
          const data = `abc abc abc abc abc abc
                   test test,test test test test`
          ;

          indexOf 的按位操作簡化

          在查找數(shù)組的某個值時,我們可以使用 indexOf() 方法。但有一種更好的方法,讓我們來看一下這個例子。

          // bad ??
          if (arr.indexOf(item) > -1) {
            // item found
          }
          if (arr.indexOf(item) === -1) {
            // item not found
          }
          // better ??
          if (~arr.indexOf(item)) {
            // item found
          }
          if (!~arr.indexOf(item)) {
            // item not found
          }

          按位 (~) 運算符將返回 true(-1 除外),反向操作只需要!~。另外,也可以使用 includes() 函數(shù)。

          if (arr.includes(item)) {
            // true if the item found
          }

          字符串轉成數(shù)字

          有一些內置的方法,例如 parseInt 和 parseFloat 可以用來將字符串轉為數(shù)字。我們還可以簡單地在字符串前提供一個一元運算符 (+) 來實現(xiàn)這一點。

          // bad ??
          let total = parseInt("453");
          let average = parseFloat("42.6");

          // better ??
          let total = +"453";
          let average = +"42.6";

          順序執(zhí)行 promise

          如果你有一堆異步或普通函數(shù)都返回 promise,要求你一個接一個地執(zhí)行,怎么辦?

          async function getData({
            const promises = [fetch("url1"), fetch("url2"), fetch("url3"), fetch("url4")];
            for (const item of promises) {
              // 打印出promise
              console.log(item);
            }

            // better ??
            for await (const item of promises) {
              // 打印出請求的結果
              console.log(item);
            }
          }

          等待所有 promise 完成

          Promise.allSettled()方法接受一組 Promise 實例作為參數(shù),包裝成一個新的 Promise 實例。只有等到所有這些參數(shù)實例都返回結果,不管是 fulfilled 還是 rejected,包裝實例才會結束

          有時候,我們不關心異步請求的結果,只關心所有的請求有沒有結束。這時,Promise.allSettled()方法就很有用

          const promises = [fetch("index.html"), fetch("https://does-not-exist/")];

          const results = await Promise.allSettled(promises);

          // 過濾出成功的請求
          const successfulPromises = results.filter((p) => p.status === "fulfilled");

          // 過濾出失敗的請求,并輸出原因
          const errors = results
          .filter((p) => p.status === "rejected")
          .map((p) => p.reason);

          交換數(shù)組元素的位置

          // bad ??
          const swapWay = (arr, i, j) => {
            const newArr = [...arr];

            let temp = newArr[i];

            newArr[i] = list[j];
            newArr[j] = temp;

            return newArr;
          };

          ES6 開始,從數(shù)組中的不同位置交換值變得容易多了

          // better ??
          const swapWay = (arr, i, j) => {
          const newArr = [...arr];

          const [newArr[j],newArr[i]] = [newArr[i],newArr[j]];

          return newArr;
          };

          使用變量作為對象鍵

          當你有一個字符串變量,并想將其用作對象中的鍵以設置一個值時可以用它

          let property = "a";

          const obj = {
            b: "b",
          };

          property = "name";

          obj[property] = "這是A";

          // {b: "b", name: "這是A"}
          console.log(obj);

          帶有范圍的隨機數(shù)生成器

          有時你需要生成隨機數(shù),但希望這些數(shù)字在一定范圍內,那就可以用這個工具。

          function randomNumber(max = 1, min = 0{
            if (min >= max) {
              return max;
            }

            return Math.floor(Math.random() * (max - min) + min);
          }

          生成隨機顏色

          function getRandomColor() {
          const colorAngle = Math.floor(Math.random() * 360);
          return `hsla(${colorAngle},100%,50%,1)`;
          }

          獲取列表最后一項

          其他語言里這個功能被做成了可以在數(shù)組上調用的方法或函數(shù),但在 JavaScript 里面,你得自己做點工作。

          let array = [0, 1, 2, 3, 4, 5, 6, 7];
          console.log(array.slice(-1)) >>> [7];

          console.log(array.slice(-2)) >>> [6, 7];

          console.log(array.slice(-3)) >>> [5, 6, 7];

          function lastItem(list{
            if (Array.isArray(list)) {
              return list.slice(-1)[0];
            }

            if (list instanceof Set) {
              return Array.from(list).slice(-1)[0];
            }

            if (list instanceof Map) {
              return Array.from(list.values()).slice(-1)[0];
            }
          }

          圖片懶加載

          在懶加載的實現(xiàn)中,有兩個關鍵的數(shù)值:一個是當前可視區(qū)域的高度,另一個是元素距離可視區(qū)域頂部的高度。

          當前可視區(qū)域的高度, 在和現(xiàn)代瀏覽器及 IE9 以上的瀏覽器中,可以用 window.innerHeight 屬性獲取。在低版本 IE 的標準模式中,可以用 document.documentElement.clientHeight 獲取,這里我們兼容兩種情況:

          const viewHeight = window.innerHeight || document.documentElement.clientHeight;

          而元素距離可視區(qū)域頂部的高度,我們這里選用 getBoundingClientRect() 方法來獲取返回元素的大小及其相對于視口的位置。對此 MDN 給出了非常清晰的解釋:

          該方法的返回值是一個 DOMRect 對象,這個對象是由該元素的 getClientRects() 方法返回的一組矩形的集合, 即:是與該元素相關的 CSS 邊框集合 。

          DOMRect 對象包含了一組用于描述邊框的只讀屬性——left、top、right 和 bottom,單位為像素。除了 width 和 height 外的屬性都是相對于視口的左上角位置而言的。

          <!DOCTYPE html>
          <html lang="en">
            <head>
              <meta charset="UTF-8" />
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />
              <meta http-equiv="X-UA-Compatible" content="ie=edge" />
              <title>Lazy-Load</title>
              <style>
                .img {
                  width: 200px;
                  height: 200px;
                  background-color: gray;
                }
                .pic {
                  // 必要的img樣式
                }
              </style>
            </head>
            <body>
              <div class="container">
                <div class="img">
                  // 注意我們并沒有為它引入真實的src
                  <img class="pic" alt="加載中" src="./images/1.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/2.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/3.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/4.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/5.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/6.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/7.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/8.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/9.png" />
                </div>
                <div class="img">
                  <img class="pic" alt="加載中" src="./images/10.png" />
                </div>
              </div>
            </body>
          </html>

          <script>
              // 獲取所有的圖片標簽
              const imgs = document.getElementsByTagName('img')
              // 獲取可視區(qū)域的高度
              const viewHeight = window.innerHeight || document.documentElement.clientHeight
              // num用于統(tǒng)計當前顯示到了哪一張圖片,避免每次都從第一張圖片開始檢查是否露出
              let num = 0
              function lazyload(){
                  for(let i=num; i<imgs.length; i++) {
                      // 用可視區(qū)域高度減去元素頂部距離可視區(qū)域頂部的高度
                      let distance = viewHeight - imgs[i].getBoundingClientRect().top
                      // 如果可視區(qū)域高度大于等于元素頂部距離可視區(qū)域頂部的高度,說明元素露出
                      if(distance >= 0 ){
                          // 給元素寫入真實的src,展示圖片
                          imgs[i].src = imgs[i].getAttribute('src')
                          // 前i張圖片已經加載完畢,下次從第i+1張開始檢查是否露出
                          num = i + 1
                      }
                  }
              }
              // 監(jiān)聽Scroll事件
              window.addEventListener('scroll', lazyload, false);
          </script>


          圖片預加載

          class PreLoadImage {
            constructor(imgNode) {
              // 獲取真實的DOM節(jié)點
              this.imgNode = imgNode;
            }

            // 操作img節(jié)點的src屬性
            setSrc(imgUrl) {
              this.imgNode.src = imgUrl;
            }
          }

          class ProxyImage {
            // 占位圖的url地址
            static LOADING_URL = "xxxxxx";

            constructor(targetImage) {
              // 目標Image,即PreLoadImage實例
              this.targetImage = targetImage;
            }

            // 該方法主要操作虛擬Image,完成加載
            setSrc(targetUrl) {
              // 真實img節(jié)點初始化時展示的是一個占位圖
              this.targetImage.setSrc(ProxyImage.LOADING_URL);
              // 創(chuàng)建一個幫我們加載圖片的虛擬Image實例
              const virtualImage = new Image();
              // 監(jiān)聽目標圖片加載的情況,完成時再將DOM上的真實img節(jié)點的src屬性設置為目標圖片的url
              virtualImage.onload = () => {
                this.targetImage.setSrc(targetUrl);
              };
              // 設置src屬性,虛擬Image實例開始加載圖片
              virtualImage.src = targetUrl;
            }
          }

          ProxyImage 幫我們調度了預加載相關的工作,我們可以通過 ProxyImage 這個代理,實現(xiàn)對真實 img 節(jié)點的間接訪問,并得到我們想要的效果。

          參考文檔

          1. 前端性能優(yōu)化原理與實踐[1]
          2. JavaScript 設計模式核?原理與應?實踐[2]
          3. 你應該了解的 25 個 JS 技巧[3]

          參考資料

          [1]

          https://juejin.cn/book/6844733750048210957/section/6844733750119514126: https://juejin.cn/book/6844733750048210957/section/6844733750119514126

          [2]

          https://juejin.cn/book/6844733790204461070/section/6844733790275780621: https://juejin.cn/book/6844733790204461070/section/6844733790275780621

          [3]

          https://mp.weixin.qq.com/s/IFmzGyz3MWOYj80qrq1Uig: https://link.juejin.cn?target=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FIFmzGyz3MWOYj80qrq1Uig

          最后



          如果你覺得這篇內容對你挺有啟發(fā),我想邀請你幫我三個小忙:

          1. 點個「在看」,讓更多的人也能看到這篇內容(喜歡不點在看,都是耍流氓 -_-)

          2. 歡迎加我微信「 sherlocked_93 」拉你進技術群,長期交流學習...

          3. 關注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。


          點個在看支持我吧,轉發(fā)就更好了



          瀏覽 37
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  99国产精品久久久久久久久久久久久 | 一级黄色电影在线看 | 天天操天天操天天 | 国外操逼视频 | 热视频亚洲欧美 |