細說JavaScript常用的18個技巧「值得收藏」

echa攻城獅 發佈 2020-06-14T18:26:54+00:00

作者:前端森林轉發連結:https://mp.weixin.qq.



作者:前端森林

轉發連結: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() 方法的對象無法進行更新響應。

關鍵字: