作者:前端森林
轉發連結:https://mp.weixin.qq.com/s/mhX6A19vX7w0Ug9aaNbbMg
引言
寫這篇文章的緣由是上周在公司前端團隊的code review時,看了一個實習小哥哥的代碼後,感覺一些剛入行不久的同學,對於真實項目中的一些js處理不是很熟練,缺乏一些技巧。
因此整理了自己開發中常用的一些js技巧,靈活的運用,會增強你解決問題的能力,也會對你的代碼簡潔性有很太的改觀。
數組去重
正常我們實現數組去重大多都是通過雙層遍歷或者indexOf的方式。
雙層for循環去重
function unique(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
利用indexOf去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log("type error!");
return;
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i]);
}
}
return array;
}
但其實有一種更簡單的方式:利用Array.from與set去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log("type error!");
return;
}
return Array.from(new Set(arr));
}
這種代碼的實現是不是很簡潔
數組轉化為對象(Array to Object)
數組轉化為對象,大多數同學首先想到的就是這種方法:
var obj = {};
var arr = ["1","2","3"];
for (var key in arr) {
obj[key] = arr[key];
}
console.log(obj)
Output:
{0: 1, 1: 2, 2: 3}
但是有一種比較簡單快速的方法:
const arr = [1,2,3]
const obj = {...arr}
console.log(obj)
Output:
{0: 1, 1: 2, 2: 3}
一行代碼就能搞定的事情為什麼還要用遍歷呢?
合理利用三元表達式
有些場景我們需要針對不同的條件,給變量賦予不同的值,我們往往會採用下面這種方式:
const isGood = true;
let feeling;
if (isGood) {
feeling = 'good'
} else {
feeling = 'bad'
}
console.log(`I feel ${feeling}`)
Output:
I feel good
但是為什麼不採用三元表達式呢?
const isGood = true;
const feeling = isGood ? 'good' : 'bad'
console.log(`I feel ${feeling}`)
Output:
I feel good
這種也就是所謂的Single line(單行)思想,其實就是代碼趨向於簡潔性。
轉換為數字類型(Convert to Number)
這種是很常見的,大家用的比較多的可能是parseInt()、Number()這種:
const age = "69";
const ageConvert = parseInt(age);
console.log(typeof ageConvert);
Output: number;
其實也可以通過+來實現轉換:
const age = "69";
const ageConvert = +age;
console.log(typeof ageConvert);
Output: number;
轉換為字符串類型(Convert to String)
轉換為字符串一般會用toString()、String()實現:
let a = 123;
a.toString(); // '123'
但也可以通過value + ""這種來實現:
let a = 123;
a + ""; // '123'
性能追蹤
如果你想測試一段js代碼的執行耗時,那麼你可以嘗試下performance:
let start = performance.now();
let sum = 0;
for (let i = 0; i < 100000; i++) {
sum += 1;
}
let end = performance.now();
console.log(start);
console.log(end);
合併對象(Combining Objects)
兩個對象合併大家用的比較多的可能就是Object.assign了:
const obj1 = { a: 1 }
const obj2 = { b: 2 }
console.log(Object.assign(obj1, obj2))
Output:
{ a: 1, b: 2 }
其實有一種更簡潔的方式:
const obj1 = { a: 1 }
const obj2 = { b: 2 }
const combinObj = { ...obj1, ...obj2 }
console.log(combinObj)
Output:
{ a: 1, b: 2 }
也就是通過展開操作符(spread operator)來實現。
短路運算(Short-circuit evaluation)
我們可以通過&&或||來簡化我們的代碼,比如:
if (isOnline) {
postMessage();
}
// 使用&&
isOnline && postMessage();
// 使用||
let name = null || "森林";
數組扁平化(Flattening an array)
數組的扁平化,我們一般會用遞歸或reduce去實現
遞歸
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i]);
}
}
return result;
}
console.log(flatten(arr));
reduce
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.reduce(function (prev, next) {
return prev.concat(Array.isArray(next) ? flatten(next) : next);
}, []);
}
console.log(flatten(arr));
但是es6提供了一個新方法 flat(depth),參數depth,代表展開嵌套數組的深度,默認是1
let arr = [1, [2, 3, [4, [5]]]];
arr.flat(3); // [1,2,3,4,5]
求冪運算
平時我們實現指數運算,用的比較多的應該是Math.pow(),比如求2^10:
console.log(Math.pow(2, 10));
在ES7中引入了指數運算符**,**具有與Math.pow()一樣的計算結果。
console.log(2 ** 10); // 輸出1024
浮點數轉為整數(Float to Integer)
我們一般將浮點數轉化為整數會用到Math.floor()、Math.ceil()、Math.round()。但其實有一個更快的方式:
console.log(~~6.95); // 6
console.log(6.95 >> 0); // 6
console.log(6.95 << 0); // 6
console.log(6.95 | 0); // 6
// >>>不可對負數取整
console.log(6.95 >>> 0); // 6
也就是使用~, >>, <<, >>>, |這些位運算符來實現取整
截斷數組
❝
如果你有修改數組長度為某固定值的需求,那麼你可以試試這個
❞
let array = [0, 1, 2, 3, 4, 5];
array.length = 3;
console.log(array);
Output: [0, 1, 2];
獲取數組中的最後一項
通常,獲取數組最後一項,我們用的比較多的是:
let arr = [0, 1, 2, 3, 4, 5];
const last = arr[arr.length - 1];
console.log(last);
Output: 5;
但我們也可以通過slice操作來實現:
let arr = [0, 1, 2, 3, 4, 5];
const last = arr.slice(-1)[0];
console.log(last);
Output: 5;
美化你的JSON
日常開發中,我們會經常用到JSON.stringify,但大家可能並不大清楚它具體有哪些參數。
它有三個參數:
- json: 必須,可以是數組或Object
- replacer: 可選值,可以是數組,也可以是方法
- space: 用什麼來進行分隔
而我們恰恰可以指定第三個參數space的值去美化我們的JSON:
Object.create(null)
❝
在Vue和Vuex的源碼中,作者都使用了Object.create(null)來初始化一個新對象。為什麼不用更簡潔的{}呢?我們來看下Object.create()的定義:
❞
Object.create(proto,[propertiesObject])
- proto:新創建對象的原型對象
- propertiesObject:可選。要添加到新對象的可枚舉(新添加的屬性是其自身的屬性,而不是其原型鏈上的屬性)的屬性。
我們對比分別通過Object.create(null)和{}創建對象的不同:
從上圖可以看到,通過{}創建的對象繼承了Object自身的方法,如hasOwnProperty、toString等,在新對象上可以直接使用。
而使用Object.create(null)創建的對象,除了自身屬性a之外,原型鏈上沒有任何屬性。
也就是我們可以通過Object.create(null)這種方式創建一個純凈的對象,我們可以自己定義hasOwnProperty、toString等方法,完全不必擔心會將原型鏈上的同名方法覆蓋掉。
拷貝數組
日常開發中,數組的拷貝是一個會經常遇到的場景。其實實現數組的拷貝有很多騷技巧。
Array.slice
const arr = [1, 2, 3, 4, 5];
const copyArr = arr.slice();
展開操作符
const arr = [1, 2, 3, 4, 5];
const copyArr = [...arr]
使用 Array 構造函數和展開操作符
const arr = [1, 2, 3, 4, 5];
const copyArr = new Array(...arr)
Array.concat
const arr = [1, 2, 3, 4, 5];
const copyArr = arr.concat();
避免多條件並列
開發中有時會遇到多個條件,執行相同的語句,也就是多個||這種:
if (status === 'process' || status === 'wait' || status === 'fail') {
doSomething()
}
這種寫法語義性、可讀性都不太好。可以通過switch case或includes這種進行改造。
switch case
switch(status) {
case 'process':
case 'wait':
case 'fail':
doSomething()
}
includes
const enum = ['process', 'wait', 'fail']
if (enum.includes(status)) {
doSomething()
}
Object.freeze()
❝
在 Vue 的文檔中介紹數據綁定和響應時,特意標註了對於經過 Object.freeze() 方法的對象無法進行更新響應。