js技巧

1. 類型檢查小工具

JavaScript 不是強(qiáng)類型語(yǔ)言,對(duì)此我推薦的最佳解決方案是 TypeScript。但有時(shí)你只是想要一個(gè)簡(jiǎn)單的類型檢查,這種時(shí)候 JavaScript 允許你使用“typeof”關(guān)鍵字。

“typeof”的問(wèn)題在于,將其用于某些原語(yǔ)和函數(shù)時(shí)效果很好,但對(duì)于數(shù)組和對(duì)象來(lái)說(shuō),由于它們都被視為“對(duì)象”,因此很難把握它們之間的區(qū)別。

const isOfType = (() => {  // create a plain object with no prototype  const type = Object.create(null);  // check for null type  type.null = x => x === null;  // check for undefined type  type.undefined = x => x === undefined;  // check for nil type. Either null or undefined  type.nil = x => type.null(x) || type.undefined(x);  // check for strings and string literal type. e.g: 's', "s", `str`, new String()  type.string = x => !type.nil(x) && (typeof x === 'string' || x instanceof String);  // check for number or number literal type. e.g: 12, 30.5, new Number()  type.number = x => !type.nil(x)    && (// NaN & Infinity have typeof "number" and this excludes that      (!isNaN(x) && isFinite(x)      && typeof x === 'number'    ) || x instanceof Number);  // check for boolean or boolean literal type. e.g: true, false, new Boolean()  type.boolean = x => !type.nil(x) && (typeof x === 'boolean' || x instanceof Boolean);  // check for array type  type.array = x => !type.nil(x) && Array.isArray(x);  // check for object or object literal type. e.g: {}, new Object(), Object.create(null)  type.object = x => ({}).toString.call(x) === '[object Object]';  // check for provided type instance  type.type = (x, X) => !type.nil(x) && x instanceof X;  // check for set type  type.set = x => type.type(x, Set);  // check for map type  type.map = x => type.type(x, Map);  // check for date type  type.date = x => type.type(x, Date);  return type;})();

2. 檢查是否為空
有時(shí)你需要知道某些內(nèi)容是否為空,并根據(jù)結(jié)果決定要使用的方法,例如檢查長(zhǎng)度、大小或是否包含任何子元素。下面這個(gè)工具打包了這些功能,你可以用它檢查 String、Object、Array、Map 和 Set 的大小。

function isEmpty(x) {  if(Array.isArray(x)    || typeof x === 'string'    || x instanceof String   ) {    return x.length === 0;  }  if(x instanceof Map || x instanceof Set) {    return x.size === 0;  }  if(({}).toString.call(x) === '[object Object]') {    return Object.keys(x).length === 0;  }  return false;}

3. 獲取列表最后一項(xiàng)
其他語(yǔ)言里這個(gè)功能被做成了可以在數(shù)組上調(diào)用的方法或函數(shù),但在 JavaScript 里面,你得自己做點(diǎn)工作。

function lastItem(list) {  if(Array.isArray(list)) {    return list.slice(-1)[0];  }  if(list instanceof Set) {    return Array.from(list).slice(-1)[0];  }  if(list instanceof Map) {    return Array.from(list.values()).slice(-1)[0];  }}

4. 帶有范圍的隨機(jī)數(shù)生成器
有時(shí)你需要生成隨機(jī)數(shù),但希望這些數(shù)字在一定范圍內(nèi),那就可以用這個(gè)工具。

function randomNumber(max = 1, min = 0) {  if(min >= max) {    return max;  }  return Math.floor(Math.random() * (max - min) + min);}

5. 隨機(jī) ID 生成器
有時(shí)你只是需要一些 ID?除非你要的是更復(fù)雜的 ID 生成器(例如 UUID),否則用不著為此安裝什么新庫(kù),下面這個(gè)選項(xiàng)足夠了。你可以從當(dāng)前時(shí)間(以毫秒為單位)或特定的整數(shù)和增量開(kāi)始生成,也可以從字母生成 ID。

// create unique id starting from current time in milliseconds// incrementing it by 1 everytime requestedconst uniqueId = (() => {  const id = (function*() {    let mil = new Date().getTime();    while (true)      yield mil += 1;  })();  return () => id.next().value;})();// create unique incrementing id starting from provided value or zero// good for temporary things or things that id resetsconst uniqueIncrementingId = ((lastId = 0) => {  const id = (function*() {    let numb = lastId;    while (true)      yield numb += 1;  })()  return (length = 12) => `${id.next().value}`.padStart(length, '0');})();// create unique id from letters and numbersconst uniqueAlphaNumericId = (() => {  const heyStack = '0123456789abcdefghijklmnopqrstuvwxyz';  const randomInt = () => Math.floor(Math.random() * Math.floor(heyStack.length))  return (length = 24) => Array.from({length}, () => heyStack[randomInt()]).join('');})();

6. 創(chuàng)建一個(gè)范圍內(nèi)的數(shù)字
Python 里我很喜歡的一個(gè)功能是 range 函數(shù),而在 JavaScript 里我經(jīng)常需要自己寫這個(gè)功能。下面是一個(gè)簡(jiǎn)單的實(shí)現(xiàn),非常適合 for…of 循環(huán)以及需要特定范圍內(nèi)數(shù)字的情況。

function range(maxOrStart, end = null, step = null) {  if(!end) {    return Array.from({length: maxOrStart}, (_, i) => i)  }  if(end <= maxOrStart) {    return [];  }  if(step !== null) {    return Array.from(      {length: Math.ceil(((end - maxOrStart) / step))},      (_, i) => (i * step) + maxOrStart    );  }  return Array.from(    {length: Math.ceil((end - maxOrStart))},    (_, i) => i + maxOrStart  );}

7. 格式化 JSON 字符串,stringify 任何內(nèi)容

我在使用 NodeJs 將對(duì)象記錄到控制臺(tái)時(shí)經(jīng)常使用這種方法。JSON.stringify 方法需要第三個(gè)參數(shù),該參數(shù)必須有多個(gè)空格以縮進(jìn)行。第二個(gè)參數(shù)可以為 null,但你可以用它來(lái)處理 function、Set、Map、Symbol 之類 JSON.stringify 方法無(wú)法處理或完全忽略的內(nèi)容。

image.gif
const stringify = (() => {  const replacer = (key, val) => {    if(typeof val === 'symbol') {      return val.toString();    }    if(val instanceof Set) {      return Array.from(val);    }    if(val instanceof Map) {      return Array.from(val.entries());    }    if(typeof val === 'function') {      return val.toString();    }    return val;  }  return (obj, spaces = 0) => JSON.stringify(obj, replacer, spaces)})();

8. 順序執(zhí)行 promise
如果你有一堆異步或普通函數(shù)都返回 promise,要求你一個(gè)接一個(gè)地執(zhí)行,這個(gè)工具就會(huì)很有用。它會(huì)獲取函數(shù)或 promise 列表,并使用數(shù)組 reduce 方法按順序解析它們。

const asyncSequentializer = (() => {  const toPromise = (x) => {    if(x instanceof Promise) { // if promise just return it      return x;    }    if(typeof x === 'function') {      // if function is not async this will turn its result into a promise      // if it is async this will await for the result      return (async () => await x())();    }    return Promise.resolve(x)  }  return (list) => {    const results = [];    return list      .reduce((lastPromise, currentPromise) => {        return lastPromise.then(res => {          results.push(res); // collect the results          return toPromise(currentPromise);        });      }, toPromise(list.shift()))      // collect the final result and return the array of results as resolved promise      .then(res => Promise.resolve([...results, res]));  }})();

9. 輪詢數(shù)據(jù)
如果你需要持續(xù)檢查數(shù)據(jù)更新,但系統(tǒng)中沒(méi)有 WebSocket,則可以使用這個(gè)工具來(lái)執(zhí)行操作。它非常適合上傳文件時(shí),想要持續(xù)檢查文件是否已完成處理的情況,或者使用第三方 API(例如 dropbox 或 uber)并且想要持續(xù)檢查過(guò)程是否完成或騎手是否到達(dá)目的地的情況。

async function poll(fn, validate, interval = 2500) {  const resolver = async (resolve, reject) => {    try { // catch any error thrown by the "fn" function      const result = await fn(); // fn does not need to be asynchronous or return promise      // call validator to see if the data is at the state to stop the polling      const valid = validate(result);      if (valid === true) {        resolve(result);      } else if (valid === false) {        setTimeout(resolver, interval, resolve, reject);      } // if validator returns anything other than "true" or "false" it stops polling    } catch (e) {      reject(e);    }  };  return new Promise(resolver);}

10. 等待所有 promise 完成

這個(gè)算不上是代碼解決方案,更多是對(duì) Promise API 的強(qiáng)化。這個(gè) API 在不斷進(jìn)化,以前我還為“allSettled”“race”和“any”做了代碼實(shí)現(xiàn),現(xiàn)在直接用 API 的就好了。

image.gif

11. 交換數(shù)組值的位置

ES6 開(kāi)始,從數(shù)組中的不同位置交換值變得容易多了。這個(gè)做起來(lái)不難,但是了解一下也不錯(cuò),

圖片

12. 條件對(duì)象鍵

我最喜歡這條技巧了,我在使用 React 更新?tīng)顟B(tài)時(shí)經(jīng)常用它。你可以將條件包裝在括號(hào)中來(lái)有條件地將一個(gè)鍵插入一個(gè) spread 對(duì)象。

圖片

13. 使用變量作為對(duì)象鍵

當(dāng)你有一個(gè)字符串變量,并想將其用作對(duì)象中的鍵以設(shè)置一個(gè)值時(shí)可以用它。

圖片

14. 檢查對(duì)象里的鍵

這是一個(gè)很好的技巧,可以幫助你檢查對(duì)象鍵。

image.gif

15. 刪除數(shù)組重復(fù)項(xiàng)

數(shù)組中經(jīng)常有重復(fù)的值,你可以使用 Set 數(shù)據(jù)結(jié)構(gòu)來(lái)消除它。它適用于許多數(shù)據(jù)類型,并且 set 有多種檢查相等性的方法,很好用。對(duì)于不同實(shí)例或?qū)ο蟮那闆r,你還是可以使用 Set 來(lái)跟蹤特定事物并過(guò)濾出重復(fù)的對(duì)象。

image.gif

16. 在 ArrayforEach 中執(zhí)行“break”和“continue”

我真的很喜歡使用數(shù)組“.forEach”方法,但有時(shí)我需要提早退出或繼續(xù)進(jìn)行下一個(gè)循環(huán),而不想用 for...loop。你可以復(fù)制“continue”語(yǔ)句行為來(lái)提前返回,但如果要復(fù)制“break”行為,則需要使用數(shù)組“.some”方法。

圖片

17. 使用別名和默認(rèn)值來(lái)銷毀

Destructuring(銷毀)是 JavaScript 最好用的功能之一,而且你可以使用“冒號(hào)”設(shè)置別名,并使用“等號(hào)”設(shè)置屬性默認(rèn)值。

image.gif

18. 可選鏈和空值合并

深入檢查對(duì)象屬性并處理 null 和 undefined 值時(shí),你可以使用幾個(gè)非常好用的 JavaScript 功能來(lái)解決常見(jiàn)的問(wèn)題。

圖片

19. 用函數(shù)擴(kuò)展類

我經(jīng)常對(duì)別人講,JavaScript 類只是構(gòu)造函數(shù)和底層的原型,不是像 Java 中那樣的真實(shí)概念。一個(gè)證據(jù)是,你可以只使用一個(gè)構(gòu)造函數(shù)來(lái)擴(kuò)展一個(gè)類。在私有內(nèi)容里這個(gè)很好用,在類里“#”這些看著很奇怪,并且用于 babel 或 WebPack 時(shí),編譯出來(lái)的代碼更少。

圖片

20. 擴(kuò)展構(gòu)造函數(shù)

類的一個(gè)問(wèn)題是你只能擴(kuò)展一個(gè)其他類。使用構(gòu)造函數(shù),你可以使用多個(gè)構(gòu)造函數(shù)來(lái)構(gòu)成一個(gè)函數(shù),這樣就會(huì)靈活多了。你可以使用函數(shù)原型的.apply 或.call 方法來(lái)實(shí)現(xiàn)。你甚至可以只擴(kuò)展函數(shù)的一部分,只要它是一個(gè)對(duì)象即可。

圖片

21. 循環(huán)任何內(nèi)容有時(shí),你需要循環(huán)任何可迭代的內(nèi)容(Set、Map、Object、Array、String 等)。這個(gè)非常簡(jiǎn)單的 forEach 函數(shù)工具就可以做到這一點(diǎn)。如果回調(diào)返回 true,它將退出循環(huán)。

function forEach(list, callback) {  const entries = Object.entries(list);  let i = 0;  const len = entries.length;  for(;i < len; i++) {    const res = callback(entries[i][1], entries[i][0], list);    if(res === true) break;  }}

22. 使函數(shù)參數(shù)為 required
這是一種確保函數(shù)調(diào)用了完成工作所需內(nèi)容的絕佳方法。你可以使用默認(rèn)參數(shù)值的特性來(lái)調(diào)用函數(shù),然后就會(huì)拋出一個(gè)錯(cuò)誤。如果調(diào)用該函數(shù)時(shí)帶上了它需要的值,則該值將替換該函數(shù),并且什么也不會(huì)發(fā)生。使用 undefined 調(diào)用也有相同的效果。

function required(argName = 'param') {  throw new Error(`"${argName}" is required`)}function iHaveRequiredOptions(arg1 = required('arg1'), arg2 = 10) {  console.log(arg1, arg2)}iHaveRequiredOptions(); // throws "arg1" is requirediHaveRequiredOptions(12); // prints 12, 10iHaveRequiredOptions(12, 24); // prints 12, 24iHaveRequiredOptions(undefined, 24); // throws "arg1" is required

23. 創(chuàng)建模塊或單例

很多時(shí)候,你需要在加載時(shí)初始化某些內(nèi)容,設(shè)置它需要的各種事物,然后就可以在應(yīng)用程序中到處使用它,而無(wú)需再做什么補(bǔ)充工作。你可以使用 IIFE 函數(shù)來(lái)做到這一點(diǎn),這個(gè)函數(shù)太好用了。這種模塊模式用來(lái)隔離事物非常好用,它可以只暴露需要交互的內(nèi)容。

圖片

24. 深度克隆對(duì)象開(kāi)發(fā)人員通常會(huì)安裝一些類似“l(fā)odash”的庫(kù)來(lái)執(zhí)行這一操作,但使用純 JavaScript 來(lái)實(shí)現(xiàn)確實(shí)也很容易。這是一個(gè)簡(jiǎn)單的遞歸函數(shù):只要是一個(gè)對(duì)象,就使用函數(shù)的構(gòu)造器將其重新初始化為一個(gè)克隆,然后對(duì)所有屬性重復(fù)該過(guò)程。

const deepClone = obj => {  let clone = obj;  if (obj && typeof obj === "object") {    clone = new obj.constructor();    Object.getOwnPropertyNames(obj).forEach(      prop => (clone[prop] = deepClone(obj[prop]))    );  }  return clone;};

25. 深度凍結(jié)對(duì)象
如果你喜歡不變性,那么這個(gè)工具你一定要常備。

const deepClone = obj => {  let clone = obj;  if (obj && typeof obj === "object") {    clone = new obj.constructor();    Object.getOwnPropertyNames(obj).forEach(      prop => (clone[prop] = deepClone(obj[prop]))    );  }  return clone;};

JSON.stringify 替換參數(shù)的威力


image.png
1.轉(zhuǎn)換字符串所有字母大小寫
let str = 'adfdf DD ssFF'
let reverseCase = (str) => {
    let res = [...str].map(item => {
        return item === item.toLowerCase() ? item.toUpperCase() : item.toLowerCase()
    }).join('')
    return res
}
console.log(reverseCase(str))  //ADFDF dd SSff
2.字符串首字母轉(zhuǎn)化大寫
let str = 'i am shi niu bi ren'
let res = str.replace(/\b[a-z]/g, (str) => { return str.toUpperCase() })
console.log(res) //I Am Shi Niu Bi Ren
3.數(shù)組隨機(jī)排列
const arr = [2, 4, 5, 6, 1, 7, 8, 9, 0, 3]
arr.sort((a, b) => {
    return Math.random() - 0.5
})
console.log(arr)
4.求數(shù)組的最大值
const arr = [2, 4, 5, 6, 1, 7, 8, 9, 0, 3]
let res = arr.reduce((pre, cur) => {
    let res = cur > pre ? cur : pre
    return res
})
console.log(res)//9

let res2 = Math.max(...arr)
console.log(res2)//9
5.求數(shù)組的隨機(jī)數(shù)
const arr = [2, 4, 5, 6, 1, 7, 8, 9, 0, 3]
let getRandomValue = (array) => {
    return array[Math.floor(Math.random() * array.length)]
}
console.log(getRandomValue(arr))

6.判斷字符串是否對(duì)稱
let str1 = 'abcdcba'
let str2 = 'edcabaa'

let compare = (str) => {
    return str.split('').reverse().join('') === str
}
console.log(compare(str2)) //false
7.判斷數(shù)組是否有重復(fù)項(xiàng)
const arr = [11, 2, 2, 33, 11, 88, 33, 99]
const arr1 = [11, 2, 33, 88, 99]

let repetition = (arr) => {
    return new Set(arr).size !== arr.length
}

console.log(repetition(arr)) //true
8.統(tǒng)計(jì)數(shù)組元素出現(xiàn)的次數(shù)
let arr = ["a", "b", "c", "f", "b", "b", " b", "d", "d"]

let count = (arr) => {
    let res = arr.reduce((preArr, curItem) => {
        preArr[curItem] = preArr[curItem] ? preArr[curItem] + 1 : 1
        return preArr
    }, {})
    return res
}

console.log(count(arr))//{ a: 1, b: 3, c: 1, f: 1, ' b': 1, d: 2 }
9.比較數(shù)組基本類型元素是否相同
let arr1 = [null, 1, 2]
let arr2 = [undefined, 1, 2]

console.log((arr1.length === arr2.length) && (arr1.every((item, index) => {
    return item === arr2[index]
})))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容