JavaScript 中有很多簡寫技巧,可以縮短代碼長度、減少冗餘,並且提高代碼的可讀性和可維護性。本文將介紹 20 個提升效率的 JS 簡寫技巧,助你告別屎山,輕鬆編寫優雅的代碼! 移除數組假值 可以使用 filter() 結合 Boolean 來簡化移除數組假值操作。假值指的是在條件判斷中被視為 ...
JavaScript 中有很多簡寫技巧,可以縮短代碼長度、減少冗餘,並且提高代碼的可讀性和可維護性。本文將介紹 20 個提升效率的 JS 簡寫技巧,助你告別屎山,輕鬆編寫優雅的代碼!
移除數組假值
可以使用 filter()
結合 Boolean
來簡化移除數組假值操作。假值指的是在條件判斷中被視為 false
的值,例如 null
、undefined
、空字元串(""
或 ''
)、0、NaN
和 false
。
傳統寫法:
let arr = [12, null, 0, 'xyz', null, -25, NaN, '', undefined, 0.5, false];
let filterArray = arr.filter(value => {
if(value) {
return value
};
});
// [12, 'xyz', -25, 0.5]
簡化寫法:
let arr = [12, null, 0, 'xyz', null, -25, NaN, '', undefined, 0.5, false];
let filterArray = arr.filter(value => Boolean(value)); // [12, 'xyz', -25, 0.5]
更簡化寫法:
let arr = [12, null, 0, 'xyz', null, -25, NaN, '', undefined, 0.5, false];
let filterArray = arr.filter(Boolean); // [12, 'xyz', -25, 0.5]
Boolean
是 JavaScript 的內置構造函數,通過傳遞一個值給它,可以將該值轉換為布爾值。在這種情況下,Boolean
構造函數作為回調函數傳遞給 filter()
方法,因此會將每個數組元素轉換為布爾值。只有轉換結果為真值的元素才會保留在新數組中。
註意:這種方式會將 0 也過濾掉,如果不需要過濾 0,需要進行額外的判斷。
數組查找
當對數組進行查找時,indexOf()
用於獲取查找項的位置。如果未找到該項,則返回值為-1
。在JavaScript中,0被視為false
,而大於或小於0的數字被視為true
。因此,需要這樣來寫:
傳統寫法:
if(arr.indexOf(item) > -1) {
}
if(arr.indexOf(item) === -1) {
}
簡化寫法:
if(~arr.indexOf(item)) {
}
if(!~arr.indexOf(item)) {
}
位非(~)運算符對除了-1之外的任何值都返回一個"真"值。對其進行取反就是簡單地使用!~
即可。另外,也可以使用includes()
函數:
if(arr.includes(item)) {
}
空值合併運算符
空值合併運算符(??
)用於為 null
或 undefined
的變數提供預設值。
傳統寫法:
const fetchUserData = () => {
return '前端充電寶';
};
const data = fetchUserData();
const username = data !== null && data !== undefined ? data : 'Guest';
簡化寫法:
const fetchUserData = () => {
return '前端充電寶';
};
const data = fetchUserData();
const username = data ?? 'CUGGZ';
除此之外,還有一個空位合併賦值運算符(??=
),用於在變數為空(null
或 undefined
)時進行賦值操作。
傳統寫法:
let variable1 = null;
let variable2 = "前端充電寶";
if (variable1 === null || variable1 === undefined) {
variable1 = variable2;
}
簡化寫法:
let variable1 = null;
let variable2 = "前端充電寶";
variable1 ??= variable2;
??=
的寫法更加簡潔和易讀。它首先檢查變數 variable1
是否為 null
或 undefined
,如果是,則將它賦值為 variable2
的值。如果 variable1
已經有一個非空的值,那麼賦值操作就不會發生。
邏輯或賦值運算符
邏輯或賦值運算符(||=
)用於為變數分配預設值。
傳統寫法:
let count;
if (!count) {
count = 0;
}
簡化寫法:
let count;
count ||= 0;
當 count
為假值(例如 undefined、null、false、0、NaN 或空字元串)時,邏輯或賦值運算符將 count
賦值為 0。否則,它會保留 count
的原始值。
多值匹配
對於多個值的匹配,可以將所有的值放入一個數組中,然後使用 indexOf(
) 方法進行檢查。indexOf()
方法是 JavaScript 數組的一個內置方法,它用於返回指定元素在數組中第一次出現的位置索引。如果數組中不存在該元素,則返回 -1。
傳統寫法:
if (value === 1 || value === 'one' || value === 2 || value === 'two') {
// ...
}
簡化寫法:
if ([1, 'one', 2, 'two'].indexOf(value) >= 0) {
// ...
}
更簡化寫法:
if ([1, 'one', 2, 'two'].includes(value)) {
// ...
}
三元表達式
使用三元表達式表示可以簡化if...else
。
傳統寫法:
let isAdmin;
if (user.role === 'admin') {
isAdmin = true;
} else {
isAdmin = false;
}
簡化寫法:
const isAdmin = user.role === 'admin' ? true : false;
更簡化寫法:
const isAdmin = user.role === 'admin';
短路求值
當將一個變數的值賦給另一個變數時,可能希望確保源變數不為 null、undefined 或空。可以編寫一個包含多個條件的長 if 語句,或者使用短路求值來簡化。
if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
let variable2 = variable1;
}
使用短路求值簡化後的代碼如下:
const variable2 = variable1 || 'new';
對於邏輯或(||)操作符,以下值被視為假:
-
false
-
0
-
空字元串("" 或 '')
-
null
-
undefined
-
NaN
所以,如果本身的值可能就是這些中的一個,就不適合使用短路求值。
短路求值還能在函數調用中避免不必要的函數執行。
傳統寫法:
function fetchData() {
if (shouldFetchData) {
return fetchDataFromAPI();
} else {
return null;
}
}
簡化寫法:
function fetchData() {
return shouldFetchData && fetchDataFromAPI();
}
當 shouldFetchData
為真值時,短路求值會繼續執行 fetchDataFromAPI()
函數並返回其結果。如果 shouldFetchData
為假值,短路求值會直接返回假值(null
),避免了不必要的函數調用。
科學計數法
可以使用科學技術法來表示數字,以省略尾部的零。例如,1e7
實際上表示 1 後面跟著 7 個零。它表示一個十進位,相當於 10,000,000。
傳統寫法:
for (let i = 0; i < 10000; i++) {}
簡化寫法:
for (let i = 0; i < 1e7; i++) {}
// 下麵的所有比較都將返回 true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;
位運算符
雙位非運算符有一個非常實用的用途,可以用它來替代Math.floor()
函數,它在執行相同的操作時速度更快。
傳統寫法:
Math.floor(4.9) === 4 //true
簡化寫法:
~~4.9 === 4 //true
指數冪運算
指數冪運算可以使用 **
來簡化。
傳統寫法:
Math.pow(2,3); // 8
Math.pow(2,2); // 4
Math.pow(4,3); // 64
簡化寫法:
2**3 // 8
2**4 // 4
4**3 // 64
從 ES7(ECMAScript 2016)開始,JavaScript 引入了指數冪運算符 **
,使指數冪運算更加簡潔。
雙非未運算符
在 JavaScript 中,雙非位運算符 ~~
可以用於將數字向下取整,類似於 Math.floor()
方法的功能。
傳統寫法:
const floor = Math.floor(6.8); // 6
簡化寫法:
const floor = ~~6.8; // 6
註意:雙非位運算符只適用於 32 位整數,即範圍為 -(2^31) 到 (2^31)-1,即 -2147483648 到 2147483647。對於大於 2147483647 或小於 0 的數字,雙非位運算符(~~
)會給出錯誤的結果,因此建議在這種情況下使用 Math.floor()
方法。
對象屬性
ES6 提供了一種更簡潔的方式來給對象賦值屬性。如果變數名與對象的鍵名相同,可以利用簡寫符號來進行賦值。
傳統寫法:
const name = '微信公眾號:前端充電寶';
const age = 18;
const person = {
name: name,
age: age
};
簡化寫法:
const name = '微信公眾號:前端充電寶';
const age = 30;
const person = {
name,
age
};
箭頭函數
箭頭函數可以簡化經典函數的寫法。
傳統寫法:
function sayHello(name) {
console.log('Hello', name);
}
setTimeout(function() {
console.log('Loaded')
}, 2000);
list.forEach(function(item) {
console.log(item);
});
簡化寫法:
sayHello = name => console.log('Hello', name);
setTimeout(() => console.log('Loaded'), 2000);
list.forEach(item => console.log(item));
如果箭頭函數只有一條語句,它會隱式地返回其求值的結果,這時可以省略 return
關鍵字:
傳統寫法:
function calcCircumference(diameter) {
return Math.PI * diameter
}
簡化寫法:
calcCircumference = diameter => (
Math.PI * diameter;
)
參數解構
如果正在使用一些流行的 Web 框架,比如 React、Vue,可能會使用數組或對象字面量形式的數據來在組件之間傳遞信息。在組件中要想使用數據對象,就需要對其進行解構。
傳統寫法:
const observable = require('mobx/observable');
const action = require('mobx/action');
const runInAction = require('mobx/runInAction');
const store = this.props.store;
const form = this.props.form;
const loading = this.props.loading;
const errors = this.props.errors;
const entity = this.props.entity;
簡化寫法:
import { observable, action, runInAction } from 'mobx';
const { store, form, loading, errors, entity } = this.props;
還可以為變數賦予新的變數名:
const { store, form, loading, errors, entity:contact } = this.props;
擴展運算符
在ES6中引入的擴展運算符可以簡化數組和對象的一些操作。
傳統寫法:
// 合併數組
const odd = [1, 3, 5];
const nums = [2, 4, 6].concat(odd);
// 克隆數組
const arr = [1, 2, 3, 4];
const arr2 = arr.slice();
簡化寫法:
// 合併數組
const odd = [1, 3, 5];
const nums = [2, 4, 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]
// 克隆數組
const arr = [1, 2, 3, 4];
const arr2 = [...arr];
與 concat()
函數不同,可以使用擴展運算符在另一個數組的任意位置插入一個數組。
const odd = [1, 3, 5];
const nums = [2, ...odd, 4, 6];
還可以將擴展運算符與ES6的解構語法結合使用:
const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a) // 1
console.log(b) // 2
console.log(z) // { c: 3, d: 4 }
擴展運算符還能用於合併對象:
傳統寫法:
let fname = { firstName : '前端' };
let lname = { lastName : '充電寶'}
let full_names = Object.assign(fname, lname);
簡化寫法:
let full_names = {...fname, ...lname};
強制參數
在傳統的 JavaScript 寫法中,為了確保函數參數被傳入一個有效值,我們需要使用條件語句來拋出一個錯誤。可以通過使用強制參數簡寫的寫法實現相同的邏輯。
傳統寫法:
function foo(bar) {
if(bar === undefined) {
throw new Error('Missing parameter!');
}
return bar;
}
簡化寫法:
mandatory = () => {
throw new Error('Missing parameter!');
}
foo = (bar = mandatory()) => {
return bar;
}
這裡定義了一個名為 mandatory
的函數,用於拋出一個錯誤,表示函數參數未被傳入。然後,在函數 foo
的參數列表中,使用賦預設值的方式來將 bar
參數設置為 mandatory()
的調用結果,如果 bar
參數未被傳入或者傳入了假值,就會觸發 mandatory()
函數的執行。
轉為布爾值
可以使用雙重邏輯非操作符將任何值轉換為布爾值。
!!23 // TRUE
!!"" // FALSE
!!0 // FALSE
!!{} // TRUE
單一的邏輯非操作符已經可以將值轉換為布爾類型並對其進行取反,所以第二個邏輯非操作符會再次對其進行取反,從而將其恢復為原始含義,並保持為布爾類型。
變數交換
可以使用數組解構來輕鬆實現變數交換。
傳統寫法(使用臨時變數完成兩個變數的交換):
let a = 5;
let b = 10;
const temp = a;
a = b;
b = temp;
簡化寫法(使用數組解構賦值完成兩個變數交換):
let a = 5;
let b = 10;
[a, b] = [b, a];
這裡創建了一個包含兩個元素的數組 [b, a]
,然後使用數組解構賦值將其中的值分別賦給變數 a
和 b
。由於左側的數組和右側的數組結構相同,所以兩個值會進行交換。
變數聲明
當需要同時聲明多個變數時,可以使用變數聲明的簡寫方法來節省時間和空間。
傳統寫法:
let x;
let y;
let z = 3;
簡化寫法:
let x, y, z = 3;
不過,這個優化有些爭議,很多人認為這麼寫會影響代碼的可讀性,因為許多變數寫到了一行,不如一個變數一行更清晰明瞭,所以可以選擇性採用。
如果有多個變數需要賦相同的值,則可以使用連等來實現。
傳統寫法:
let a = 100;
let b = 100;
let c = 100;
簡化寫法:
let a = b = c = 100;
For 迴圈
JavaScript 中傳統的 for 迴圈語法使用數組的長度作為迭代器來遍曆數組。還有很多 for 迴圈的快捷方式提供了在數組中迭代對象的不同方法,例如:
-
for...of
:用於遍歷內置字元串、數組、類數組對象、NodeList。 -
for...in
:用於訪問數組的索引和對對象字面量進行遍歷,並記錄屬性名稱和值的字元串。 -
Array.forEach
:使用回調函數對數組元素及其索引執行操作。
傳統寫法:
for (let i = 0; i < arr.length; i++) {
console.log("item: ", arr[i]);}
}
簡化寫法:
for (let str of arr) {
console.log("item: ", str);
}
arr.forEach((str) => {
console.log("item: ", str);
});
for (let index in arr) {
console.log(index, arr[index]);
}
對於對象字面量,也可以使用 for...in
來遍歷:
const obj = { a: 1, b: 3, c: 5 };
for (let key in obj) {
console.log(key, obj[key]);
}