優雅編碼 | javascript代碼優化的15個小知識

雖然已經和 javascript 打交道很長時間了,但有時可能沒有更新最新的特性,這些特性可以解決日常的一些問題,而不需要編寫額外的代碼。

在這里,收集總結了編寫優雅代碼的經驗,對代碼優化及review有一定的幫助。

1、如何在JavaScript中檢查空字符串/undefined/null?

判斷一個變量是否為空字符串、undefined、null,在與后臺API聯調時特別常見。

!!data

const items = ["", null, undefined];
for (const item of items) {
    console.log(!!item);
}

使用類型轉換 Boolean(data)

const items = ["", null, undefined];
for (const item of items) {
    console.log(Boolean(item));
}

兩種方法實現了相同的功能,將變量類型轉換為布爾值。

  • 對于nullundefined0000""false,它將返回false
  • 對于字符串"0" 和空格" ",它返回true

2、小數四舍五入

這里列舉四種實現方式

parseFloat

parseFloat() 函數解析一個參數(必要時先轉換為字符串)并返回一個浮點數。

const FLOOR_NUMBER = 3.141592653;
console.log(parseFloat(FLOOR_NUMBER).toFixed(2));   // 3.14

Math.round

Math.round() 函數返回一個數字四舍五入后最接近的整數。

const FLOOR_NUMBER = 3.141592653;
console.log(Math.round(FLOOR_NUMBER * 100 + Number.EPSILON) / 100);

Number() 構造函數創建一個 Number 對象。

將字符串轉換為十進制

const FLOOR_NUMBER = 3.141592653;
const strNumber = FLOOR_NUMBER.toFixed(2); // => '3.14'
console.log(Number(strNumber)); // => 3.14

使用Lodash

const _ = require("lodash");
const FLOOR_NUMBER = 3.141592653;
console.log(_.floor(FLOOR_NUMBER, 2));

3、對象數組按照指定key排序

實現的方式有幾種,這里列舉三種供參考

使用Lodash

Lodash 是一個一致性、模塊化、高性能的 javascript 實用工具庫,俗稱下劃線 _

_.sortBy(collection, [iteratees=[_.identity]])

創建一個元素數組。 以 iteratee 處理的結果升序排序。 這個方法執行穩定排序,也就是說相同元素會保持原始排序。 iteratees 調用1個參數: (value)。

const _ = require("lodash");
var users = [
    { user: "fred", age: 48 },
    { user: "barney", age: 36 },
    { user: "fred", age: 40 },
    { user: "barney", age: 34 },
];

_.sortBy(users, function (o) {
    return o.user;
}); // 結果為: [{ user: 'barney', age: 36 },{ user: 'barney', age: 34 },{ user: 'fred', age: 48 },{ user: 'fred', age: 40 }]

_.sortBy(users, ["user", "age"]); // 結果為: [{ user: 'barney', age: 34 },{ user: 'barney', age: 36 },{ user: 'fred', age: 40 },{ user: 'fred', age: 48 }]

_.sortBy(users, "user", function (o) {
    return Math.floor(o.age / 10);
}); // 結果為: [{ user: 'barney', age: 36 },{ user: 'barney', age: 34 },{ user: 'fred', age: 48 },{ user: 'fred', age: 40 }]

使用ES6

var users = [
    { user: "fred", age: 48 },
    { user: "barney", age: 36 },
    { user: "fred", age: 40 },
    { user: "barney", age: 34 },
];

// 按照age排序
const result = users.sort(function (a, b) {
    return a.age - b.age;
});
console.log(result);  // [{ user: 'barney', age: 34 }, { user: 'barney', age: 36 },{ user: 'fred', age: 40 },{ user: 'fred', age: 48 }]

4、對象遍歷

每個ECMAScript版本都采用不同的方式遍歷對象。

ES5 可以使用以下方法

  • Object.keys() 方法會返回一個由一個給定對象的自身可枚舉屬性組成的數組,數組中屬性名的排列順序和正常循環遍歷該對象時返回的順序一致 。

  • forEach() 方法對數組的每個元素執行一次給定的函數

const myinfo = { name: "devpoint", city: "Shenzhen" };
Object.keys(myinfo).forEach((key) => {
    console.log(key, "=", myinfo[key]);
}); 

ES6中可以使用 for...of

for...of語句在可迭代對象(包括 ArrayMapSetStringTypedArrayarguments 對象等等)上創建一個迭代循環,調用自定義迭代鉤子,并為每個不同屬性的值執行語句。

const myinfo = { name: "devpoint", city: "Shenzhen" };

for (const key of Object.keys(myinfo)) {
    console.log(key, "=", myinfo[key]);
}

ES8使用Object.entries()

Object.entries() 方法返回一個給定對象自身可枚舉屬性的鍵值對數組,其排列與使用 for...in 循環遍歷該對象時返回的順序一致(區別在于 for-in 循環還會枚舉原型鏈中的屬性)。

Object.entries(myinfo).forEach(([key, value]) => console.log(key, "=", value));

也可以這樣:

for (const [key, value] of Object.entries(myinfo)) {
    console.log(key, "=", value);
}

使用Lodash

const _ = require("lodash");
const myinfo = { name: "devpoint", city: "Shenzhen" };

_.forEach(myinfo, (value, key) => {
    console.log(key, "=", value);
});

5、event.stopPropagation()、event.preventDefault() 和 return false 區別

event.stopPropagation() 阻止事件的冒泡方法,不讓事件向 documen上蔓延,但是默認事件任然會執行,當你掉用這個方法的時候,如果點擊一個連接,這個連接仍然會被打開;

event.preventDefault() 阻止默認事件的方法,調用此方法是,連接不會被打開,但是會發生冒泡,冒泡會傳遞到上一層的父元素;

return false 比較暴力,會同時阻止事件冒泡也會阻止默認事件;寫上此代碼,連接不會被打開,事件也不會傳遞到上一層的父元素;可以理解為return false就等于同時調用了event.stopPropagation()event.preventDefault()

$(".header a").click(function (e) {
    event.stopPropagation(); //不會打印 devpoint ,但是頁面會跳轉;
});
$(".header").click(function () {
    console.log("devpoint"); 
});
$(".header").click(function () {
    console.log("devpoint"); 
});
$(".header a").click(function (e) {
    event.preventDefault(); // 頁面不會跳轉,但會打印 devpoint;
});

6、如何獲取當前url

這是比較常見的,使用方法:window.location.href

7、如何判斷對象是否存在某個KEY?

如判斷對象中是否存在鍵值:title

使用操作符

const info = {
    title: "devpoint",
};
const detail = {
    content: "Hello",
};
const find = "title";
const result = find in info;
const result2 = find in detail;
console.log(result); // true
console.log(result2); // false

使用hasOwnProperty

const info = {
    title: "devpoint",
};
const detail = {
    content: "Hello",
};
const find = "title";
const result = info.hasOwnProperty(find);
const result2 = info.hasOwnProperty(detail);
console.log(result); // true
console.log(result2); // false

直接讀取key值

const info = {
    title: "devpoint",
};
const detail = {
    content: "Hello",
};
const find = "title";
const result = info[find] !== undefined;
const result2 = detail[find] !== undefined;
console.log(result); // true
console.log(result2); // false

8、 如何插入元素到數組指定索引位置?

在特定索引位置附加1個元素,這里討論的問題排除頭部和尾部的情況,如在索引為2后面插入元素devpoint

const items = ["info", "name", "age", "day"];
const insertItem = "devpoint";
items.splice(2, 0, insertItem);
console.log(items); // [ 'info', 'name', 'devpoint', 'age', 'day' ]

附加多個元素,也是適用的。

const items = ["info", "name", "age", "day"];
const insert1 = "devpoint";
const insert2 = "https";
items.splice(2, 0, insert1, insert2);
console.log(items); // [ 'info', 'name', 'devpoint', 'https', 'age', 'day' ]

將1個數組所有元素附加到指定索引后面,如下:

const items = ["info", "name", "age", "day"];
const news = ["devpoint", "https"];
items.splice(2, 0, ...news);
console.log(items); // [ 'info', 'name', 'devpoint', 'https', 'age', 'day' ]

9、如何合并兩個數組并刪除重復項?

在開發中,合并數組并刪除重復項是比較常見的需求。

使用Lodash

const _ = require("lodash");
const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020, 2021];
const newItem = _.union(item1, item2);
console.log(newItem); // [ 2021, 2022, 2023, 2019, 2020 ]

使用數組方法filtercontact

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020, 2021];

const tmpItem = item1.concat(item2); // [ 2021, 2022, 2023, 2019, 2020, 2021 ]
const newItem = tmpItem.filter((val, pos) => tmpItem.indexOf(val) === pos); // [ 2021, 2022, 2023, 2019, 2020 ]

使用set

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020, 2021];

const newItem = [...new Set([...item1, ...item2])]; // [ 2021, 2022, 2023, 2019, 2020 ]

10、如何在字符串中查找字符并替換為空?

使用replace

let str = "developpoint";
const findStr = "elop";
str = str.replace(findStr, ""); // devpoint
console.log(str);

使用正則表達式

let str = "developpoint";
const findStr = "elop";
str = str.replace(new RegExp(findStr), "");

11、如何在數組中追加新的元素?

在過去的JavaScript版本中,是通過使用apply方法來實現的。

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020];

Array.prototype.push.apply(item2, item1);
console.log(item2); // [ 2019, 2020, 2021, 2022, 2023 ]

使用ES6

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020];

item2.push(...item1);
console.log(item2); // [ 2019, 2020, 2021, 2022, 2023 ]

12、如何判斷一個對象是否為數組?

判斷一個對象是否為數組,使用場景也是比較常見的,同樣可以使用Lodash,這里不做詳細介紹了,有興趣可以去看看文檔

在ES6之前的版本可以通過下面的方式來判斷是否為數組(可以兼容舊的瀏覽器),為了方便,三種方式寫在一起。

const arrayYears = [2021, 2022, 2023];
const objYears = { value: "2021" };

const isArray = (() => {
    return {
        byInstanceof: (array) => {
            return array instanceof Array;
        },
        byConstructor: (array) => {
            return array.constructor.toString().indexOf("Array") > -1;
        },
        byPrototype: (array) => {
            return Object.prototype.toString.call(array) === "[object Array]";
        },
    };
})();

console.log(isArray.byInstanceof(arrayYears)); // true
console.log(isArray.byConstructor(arrayYears)); // true
console.log(isArray.byPrototype(arrayYears)); // true

console.log(isArray.byInstanceof(objYears)); // false
console.log(isArray.byConstructor(objYears)); // false
console.log(isArray.byPrototype(objYears)); // false

使用ES6

使用ES6就簡潔多了。

const arrayYears = [2021, 2022, 2023];
const objYears = { value: "2021" };

const isArray = (array) => {
    return Array.isArray(array);
};
console.log(isArray(arrayYears)); // true
console.log(isArray(objYears)); // false

13、如何解析URL中的參數?

當在處理URL的時候,經常遇到需要解析URL中的參數,并獲取其值。

使用正則

const getQueryStringParams = (query) => {
    return query
        ? (/^[?#]/.test(query) ? query.slice(1) : query)
              .split("&")
              .reduce((params, param) => {
                  const [key, value] = param.split("=");
                  params[key] = value
                      ? decodeURIComponent(value.replace(/\+/g, " "))
                      : "";
                  return params;
              }, {})
        : {};
};
const params = getQueryStringParams("?wd=devpoint"); // { wd: 'devpoint' }
console.log(params); // { wd: 'devpoint' }

使用URLSearchParams

URLSearchParams 接口定義了一些實用的方法來處理 URL 的查詢字符串。擁有包括appenddeleteentries等方法,詳見介紹

const getQueryStringParams = (strUrl) => {
    return new URL(strUrl).searchParams;
};
const url = "https://www.baidu.com/s/?wd=devpoint";
const params = getQueryStringParams(url); // URLSearchParams { 'wd' => 'devpoint' }
console.log(params.get("wd")); // devpoint

14、如何獲取對象的長度(key數量)?

大部份情況下,我們會檢查數組的長度,但如果要獲取對象的長度呢?下面兩種方法是獲取對象長度的最佳方法。

使用Lodash

const _ = require("lodash");
const obj = {
    title: "devpoint",
    city: "Shenzhen",
    type: "blog",
};
const objSize = _.size(obj);
console.log(objSize); // 3

使用ES6

const obj = {
    title: "devpoint",
    city: "Shenzhen",
    type: "blog",
};
const objSize = Object.keys(obj).length;
console.log(objSize); // 3

15、如何將字符串轉換為對象數組?

當從無法控制的第三方API獲取一些數據時,就會出現這種情況。如何將字符串轉換為對象數組以在應用程序中更好的使用?以下是獲得此結果的最簡單方法。

const apiData = "Option 1|false|Option 2|false|Option 3|false|Option 4|true";

const formatToArray = (str) => {
    return str.split("|").reduce((arrayResult, item, index, arrData) => {
        if (index % 2 === 0) {
            const [option, value] = [item, JSON.parse(arrData[index + 1])];
            arrayResult.push({ option, value });
        }
        return arrayResult;
    }, []);
};

console.log(formatToArray(apiData));

輸出的數據格式為:

[
  { option: 'Option 1', value: false },
  { option: 'Option 2', value: false },
  { option: 'Option 3', value: false },
  { option: 'Option 4', value: true }
]

javascript的靈活性,使得編寫優雅的代碼方法多種多樣,需要去深入研究并總結,今天的分享就到此。