1. 如何寫出干凈的 JavaScript 代碼

        共 16538字,需瀏覽 34分鐘

         ·

        2021-09-02 17:37

        一段干凈的代碼,你在閱讀、重用和重構(gòu)的時(shí)候都能非常輕松。編寫干凈的代碼非常重要,因?yàn)樵谖覀內(nèi)粘5墓ぷ髦?,你不是僅僅是在為自己寫代碼。實(shí)際上,你還需要考慮一群需要理解、編輯和構(gòu)建你的代碼的同事。

        1. 變量

        使用有意義的名稱

        變量的名稱應(yīng)該是可描述,有意義的, JavaScript 變量都應(yīng)該采用駝峰式大小寫 ( camelCase) 命名。

        // Don't ?
        const foo = "[email protected]";
        const bar = "John";
        const age = 23;
        const qux = true;

        // Do ?
        const email = "[email protected]";
        const firstName = "John";
        const age = 23;
        const isActive = true

        布爾變量通常需要回答特定問題,例如:

        isActive 
        didSubscribe 
        hasLinkedAccount

        避免添加不必要的上下文

        當(dāng)對(duì)象或類已經(jīng)包含了上下文的命名時(shí),不要再向變量名稱添加冗余的上下文。

        // Don't ?
        const user = {
          userId"296e2589-7b33-400a-b762-007b730c8e6d",
          userEmail"[email protected]",
          userFirstName"John",
          userLastName"Doe",
          userAge23,
        };

        user.userId;

        // Do ?
        const user = {
          id"296e2589-7b33-400a-b762-007b730c8e6d",
          email"[email protected]",
          firstName"John",
          lastName"Doe",
          age23,
        };

        user.id;

        避免硬編碼值

        確保聲明有意義且可搜索的常量,而不是直接插入一個(gè)常量值。全局常量可以采用 SCREAMING_SNAKE_CASE 風(fēng)格命名。

        // Don't ?
        setTimeout(clearSessionData, 900000);

        // Do ?
        const SESSION_DURATION_MS = 15 * 60 * 1000;

        setTimeout(clearSessionData, SESSION_DURATION_MS);

        2. 函數(shù)

        使用有意義的名稱

        函數(shù)名稱需要描述函數(shù)的實(shí)際作用,即使很長(zhǎng)也沒關(guān)系。函數(shù)名稱通常使用動(dòng)詞,但返回布爾值的函數(shù)可能是個(gè)例外 — 它可以采用 是或否 問題的形式,函數(shù)名也應(yīng)該是駝峰式的。

        // Don't ?
        function toggle({
          // ...
        }

        function agreed(user{
          // ...
        }

        // Do ?
        function toggleThemeSwitcher({
          // ...
        }

        function didAgreeToAllTerms(user{
          // ...
        }

        使用默認(rèn)參數(shù)

        默認(rèn)參數(shù)比 && || 或在函數(shù)體內(nèi)使用額外的條件語句更干凈。

        // Don't ?
        function printAllFilesInDirectory(dir{
          const directory = dir || "./";
          //   ...
        }

        // Do ?
        function printAllFilesInDirectory(dir = "./"{
          // ...
        }

        限制參數(shù)的數(shù)量

        盡管這條規(guī)則可能有爭(zhēng)議,但函數(shù)最好是有3個(gè)以下參數(shù)。如果參數(shù)較多可能是以下兩種情況之一:

        • 該函數(shù)做的事情太多,應(yīng)該拆分。
        • 傳遞給函數(shù)的數(shù)據(jù)以某種方式相關(guān),可以作為專用數(shù)據(jù)結(jié)構(gòu)傳遞。
        // Don't ?
        function sendPushNotification(title, message, image, isSilent, delayMs{
          // ...
        }

        sendPushNotification("New Message""...""http://..."false1000);

        // Do ?
        function sendPushNotification({ title, message, image, isSilent, delayMs }{
          // ...
        }

        const notificationConfig = {
          title"New Message",
          message"...",
          image"http://...",
          isSilentfalse,
          delayMs1000,
        };

        sendPushNotification(notificationConfig);

        避免在一個(gè)函數(shù)中做太多事情

        一個(gè)函數(shù)應(yīng)該一次做一件事,這有助于減少函數(shù)的大小和復(fù)雜性,使測(cè)試、調(diào)試和重構(gòu)更容易。

        / Don't ?
        function pingUsers(users) {
          users.forEach((user) => {
            const userRecord = database.lookup(user);
            if (!userRecord.isActive()) {
              ping(user);
            }
          });
        }

        // Do ?
        function pingInactiveUsers(users) {
          users.filter(!isUserActive).forEach(ping);
        }

        function isUserActive(user) {
          const userRecord = database.lookup(user);
          return userRecord.isActive();
        }

        避免使用布爾標(biāo)志作為參數(shù)

        函數(shù)含有布爾標(biāo)志的參數(shù)意味這個(gè)函數(shù)是可以被簡(jiǎn)化的。

        // Don't ?
        function createFile(name, isPublic{
          if (isPublic) {
            fs.create(`./public/${name}`);
          } else {
            fs.create(name);
          }
        }

        // Do ?
        function createFile(name{
          fs.create(name);
        }

        function createPublicFile(name{
          createFile(`./public/${name}`);
        }

        避免寫重復(fù)的代碼

        如果你寫了重復(fù)的代碼,每次有邏輯改變,你都需要改動(dòng)多個(gè)位置。

        // Don't ?
        function renderCarsList(cars{
          cars.forEach((car) => {
            const price = car.getPrice();
            const make = car.getMake();
            const brand = car.getBrand();
            const nbOfDoors = car.getNbOfDoors();

            render({ price, make, brand, nbOfDoors });
          });
        }

        function renderMotorcyclesList(motorcycles{
          motorcycles.forEach((motorcycle) => {
            const price = motorcycle.getPrice();
            const make = motorcycle.getMake();
            const brand = motorcycle.getBrand();
            const seatHeight = motorcycle.getSeatHeight();

            render({ price, make, brand, nbOfDoors });
          });
        }

        // Do ?
        function renderVehiclesList(vehicles{
          vehicles.forEach((vehicle) => {
            const price = vehicle.getPrice();
            const make = vehicle.getMake();
            const brand = vehicle.getBrand();

            const data = { price, make, brand };

            switch (vehicle.type) {
              case "car":
                data.nbOfDoors = vehicle.getNbOfDoors();
                break;
              case "motorcycle":
                data.seatHeight = vehicle.getSeatHeight();
                break;
            }

            render(data);
          });
        }

        避免副作用

        在 JavaScript 中,你應(yīng)該更喜歡函數(shù)式模式而不是命令式模式。換句話說,大多數(shù)情況下我們都應(yīng)該保持函數(shù)純。副作用可能會(huì)修改共享狀態(tài)和資源,從而導(dǎo)致一些奇怪的問題。所有的副作用都應(yīng)該集中管理,例如你需要更改全局變量或修改文件,可以專門寫一個(gè) util 來做這件事。

        // Don't ?
        let date = "21-8-2021";

        function splitIntoDayMonthYear({
          date = date.split("-");
        }

        splitIntoDayMonthYear();

        // Another function could be expecting date as a string
        console.log(date); // ['21', '8', '2021'];

        // Do ?
        function splitIntoDayMonthYear(date{
          return date.split("-");
        }

        const date = "21-8-2021";
        const newDate = splitIntoDayMonthYear(date);

        // Original vlaue is intact
        console.log(date); // '21-8-2021';
        console.log(newDate); // ['21', '8', '2021'];

        另外,如果你將一個(gè)可變值傳遞給函數(shù),你應(yīng)該直接克隆一個(gè)新值返回,而不是直接改變?cè)撍?/p>

        // Don't ?
        function enrollStudentInCourse(course, student{
          course.push({ student, enrollmentDateDate.now() });
        }

        // Do ?
        function enrollStudentInCourse(course, student{
          return [...course, { student, enrollmentDateDate.now() }];
        }

        3. 條件語句

        使用非負(fù)條件

        // Don't ?
        function isUserNotVerified(user{
          // ...
        }

        if (!isUserNotVerified(user)) {
          // ...
        }

        // Do ?
        function isUserVerified(user{
          // ...
        }

        if (isUserVerified(user)) {
          // ...
        }

        盡可能使用簡(jiǎn)寫

        // Don't ?
        if (isActive === true) {
          // ...
        }

        if (firstName !== "" && firstName !== null && firstName !== undefined) {
          // ...
        }

        const isUserEligible = user.isVerified() && user.didSubscribe() ? true : false;

        // Do ?
        if (isActive) {
          // ...
        }

        if (!!firstName) {
          // ...
        }

        const isUserEligible = user.isVerified() && user.didSubscribe();

        避免過多分支

        盡早 return 會(huì)使你的代碼線性化、更具可讀性且不那么復(fù)雜。

        // Don't ?
        function addUserService(db, user{
          if (!db) {
            if (!db.isConnected()) {
              if (!user) {
                return db.insert("users", user);
              } else {
                throw new Error("No user");
              }
            } else {
              throw new Error("No database connection");
            }
          } else {
            throw new Error("No database");
          }
        }

        // Do ?
        function addUserService(db, user{
          if (!db) throw new Error("No database");
          if (!db.isConnected()) throw new Error("No database connection");
          if (!user) throw new Error("No user");

          return db.insert("users", user);
        }

        優(yōu)先使用 map 而不是 switch 語句

        既能減少復(fù)雜度又能提升性能。

        // Don't ?
        const getColorByStatus = (status) => {
          switch (status) {
            case "success":
              return "green";
            case "failure":
              return "red";
            case "warning":
              return "yellow";
            case "loading":
            default:
              return "blue";
          }
        };

        // Do ?
        const statusColors = {
          success"green",
          failure"red",
          warning"yellow",
          loading"blue",
        };

        const getColorByStatus = (status) => statusColors[status] || "blue";

        使用可選鏈接

        const user = {
          email"[email protected]",
          billing: {
            iban"...",
            swift"...",
            address: {
              street"Some Street Name",
              state"CA",
            },
          },
        };

        // Don't ?
        const email = (user && user.email) || "N/A";
        const street =
          (user &&
            user.billing &&
            user.billing.address &&
            user.billing.address.street) ||
          "N/A";
        const state =
          (user &&
            user.billing &&
            user.billing.address &&
            user.billing.address.state) ||
          "N/A";

        // Do ?
        const email = user?.email ?? "N/A";
        const street = user?.billing?.address?.street ?? "N/A";
        const street = user?.billing?.address?.state ?? "N/A";

        4.并發(fā)

        避免回調(diào)

        回調(diào)很混亂,會(huì)導(dǎo)致代碼嵌套過深,使用 Promise 替代回調(diào)。

        // Don't ?
        getUser(function (err, user{
          getProfile(user, function (err, profile{
            getAccount(profile, function (err, account{
              getReports(account, function (err, reports{
                sendStatistics(reports, function (err{
                  console.error(err);
                });
              });
            });
          });
        });

        // Do ?
        getUser()
          .then(getProfile)
          .then(getAccount)
          .then(getReports)
          .then(sendStatistics)
          .catch((err) => console.error(err));

        // or using Async/Await ??

        async function sendUserStatistics({
          try {
            const user = await getUser();
            const profile = await getProfile(user);
            const account = await getAccount(profile);
            const reports = await getReports(account);
            return sendStatistics(reports);
          } catch (e) {
            console.error(err);
          }
        }

        5. 錯(cuò)誤處理

        處理拋出的錯(cuò)誤和 reject 的 promise

        / Don't ?
        try {
          // Possible erronous code
        } catch (e) {
          console.log(e);
        }

        // Do ?
        try {
          // Possible erronous code
        } catch (e) {
          // Follow the most applicable (or all):
          // 1- More suitable than console.log
          console.error(e);

          // 2- Notify user if applicable
          alertUserOfError(e);

          // 3- Report to server
          reportErrorToServer(e);

          // 4- Use a custom error handler
          throw new CustomError(e);
        }

        6.注釋

        只注釋業(yè)務(wù)邏輯

        可讀的代碼使你免于過度注釋,因此,你應(yīng)該只注釋復(fù)雜的邏輯。

        // Don't ?
        function generateHash(str{
          // Hash variable
          let hash = 0;

          // Get the length of the string
          let length = str.length;

          // If the string is empty return
          if (!length) {
            return hash;
          }

          // Loop through every character in the string
          for (let i = 0; i < length; i++) {
            // Get character code.
            const char = str.charCodeAt(i);

            // Make the hash
            hash = (hash << 5) - hash + char;

            // Convert to 32-bit integer
            hash &= hash;
          }
        }

        // Do ?
        function generateHash(str{
          let hash = 0;
          let length = str.length;
          if (!length) {
            return hash;
          }

          for (let i = 0; i < length; i++) {
            const char = str.charCodeAt(i);
            hash = (hash << 5) - hash + char;
            hash = hash & hash; // Convert to 32bit integer
          }
          return hash;
        }

        使用版本控制

        在代碼里不需要保留歷史版本的注釋,想查的話你直接用 git log 就可以搜到。。

        // Don't ?
        /**
         * 2021-7-21: Fixed corner case
         * 2021-7-15: Improved performance
         * 2021-7-10: Handled mutliple user types
         */

        function generateCanonicalLink(user{
          // const session = getUserSession(user)
          const session = user.getSession();
          // ...
        }

        // Do ?
        function generateCanonicalLink(user{
          const session = user.getSession();
          // ...
        }

        好了,去寫出你漂亮的代碼吧!??

        螞蟻前端正急缺人才,如果你想加入我們,歡迎加我微信和我聯(lián)系。另外如果你想加入前端、面試、理財(cái)?shù)冉涣魅?,或者你有任何其他事情想和我交流也可以添加我的個(gè)人微信 1076629390 。

        文中如有錯(cuò)誤,歡迎在后臺(tái)和我留言,如果這篇文章幫助到了你,歡迎點(diǎn)贊、在看和關(guān)注。你的點(diǎn)贊、在看和關(guān)注是對(duì)我最大的支持!

        點(diǎn)贊、在看支持作者??

        瀏覽 35
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 我~慢点~好爽好大~男男动漫 | 黄色在线免费观看网站 | 亚洲免费在线 | 超碰大香蕉97 | 性生交大片免费动作 |