30秒能夠理解的有用js代碼片斷

原文基礎上增長了其它方法以及註釋等,進行了小幅度修改,便於閱讀
注意箭頭函數有無 {}會影響是否須要再return

原文地址javascript

Adapter

適配器,如下大多利用閉包返回函數和...操做符(剩餘操做符/擴展操做符)html

promise化(promisify)

轉換異步函數以返回一個promise。至關於node的util.promisify
使用currying返回一個函數,返回一個調用原始函數的Promise。使用... rest運算符傳入全部參數。java

const promisify = func => {
        return (...args) =>{
            return new Promise((resolve, reject) => {
                return func(...args,(err,result) =>{
                    return err ? reject(err) : resolve(result)
                })
            })
        }
    }
    // const delay = promisify((d, cb) => setTimeout(cb, d))
    // delay(2000).then(() => console.log('Hi!')) -> Promise resolves after 2s

可變參數函數轉爲數組參數函數

接受一個可變參數函數並返回一個閉包,該閉包接受一個參數數組映射到該函數的輸入。 使用閉包和展開運算符(...)將參數數組映射到函數的輸入。node

const spreadOver = fn =>{
        return argsArr =>{
            return fn(...argsArr)
        }
    }
    /*
    const arrayMax = spreadOver(Math.max)
    arrayMax([1,2,3]) // -> 3
    arrayMax([1,2,4]) // -> 4
    */
    // 簡單點能夠
    // Math.max(...[1,3,5])

Array

數組最大值

Math.max()和擴展操做符...python

const arrayMax = arr => Math.max(...arr)

數組中去除假值

const compact = arr => arr.filter(Boolean)

統計某項出現的次數

const countOccurrences = (arr, value) => {
        return arr.reduce((a,v) =>{
            return v  === value ? a + 1: a + 0
        },0)
    }

統計數組元素出現次數

const countedNames = (arr) => {
        return arr.reduce(function (accr, name) {
            if (name in accr) {
                accr[name]++;
            }
            else {
                accr[name] = 1;
            }
            return accr;
        }, {});
    }
    // countedNames is:
    // { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

深度扁平(map)

利用Array.concat()...擴展操做符以及遞歸git

const deepFlatten = arr => {
       return [].concat(...arr.map((v) =>{
           return Array.isArray(v) ? deepFlatten(v) : v
       }))
   }

找出兩個數組的不一樣項

利用set.has()filtergithub

const difference = (arr1, arr2) =>{
        const s = new Set(arr2)
        return arr1.filter(x => !s.has(x))
    }

去重

const distinct = arr => [...new Set(arr)]
    const distinct = arr => [Array.from(new Set(arr))]
    const distinct = arr => {
        return arr.filter((i) => arr.indexOf(i) !== arr.lastIndexOf(i))
    }

過濾非惟一值

const filterNonUnique = arr =>{
        return arr.filter((i) => arr.indexOf(i) === arr.lastIndexOf(i))
    }

扁平一層(reduce)

const flatten = arr => arr.reduce((a, v) => a.concat(v), [])

扁平等級(depth)

根據depth等級來扁平,默認爲1web

const flattenDepth = (arr, depth = 1) =>{
        if (depth ===1) {
        return arr.reduce((a, v) => a.concat(v), [])
        }
        return  arr.reduce((a, v) => {
            return a.concat(Array.isArray(v) ? flattenDepth(v, depth-1) : v)
        }, [])
    }

根據範圍填充

默認0到end正則表達式

const initialWithRange = (end, start = 0) =>{
        return Array.from({length:end + 1 - start}).map((v, i) =>{
            return i + start
        })
    }
    const initialWithRange = (end, start = 0) =>{
        return new Array(end + 1 - start).fill().map((v, i) =>{
            return i + start
        })
    }

兩個數組的交叉值

const intersection = (arr1, arr2) =>{
    const s = new Set(arr2)
    return arr1.filter((x) => s.has(x))
 }

挑選(pick)

從對象中挑選與給定鍵對應的鍵值對。算法

const pick = (obj, arr) =>
      arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
    const pick = (obj, arr) => {
        return arr.reduce((acc, curr) => {
            curr in obj && (acc[curr] = obj[curr])
            return acc
        }, {})
    }
    // 本質,遍歷檢查一遍
    const pick = (obj, arr) => {
        var temp = {}
        arr.forEach((item, index) => {
            if (item in obj){
                temp[item] = obj[item]
            }
        })
        return temp
    }

隨機取數(sample)

同時也適用於字符串

const sample = arr =>{
        return arr[Math.floor(Math.random()*arr.length)]
    }

打亂(shuffle)

// 初級版
    const shuffle = arr => arr.sort(() => Math.random() - 0.5)
// random order
    function shuffle(array) {
        var random = array.map(Math.random)
        return array.sort(function(a, b) {
            return random[a] - random[b]
        })
    }
// Fisher–Yates(費歇爾洗牌算法)
    function shuffle(arr) {
        for (let i = arr.length; i > 0; i--){
            //下面一行的';'不可去掉,不然會報錯
            let j = Math.floor(Math.random() *i);
            [arr[i-1], arr[j]] = [arr[j], arr[i-1]]
        }
        return arr
    }

類似值

const similarity = (arr1, arr2) =>{
    return arr1.filter((item, i) => {
        return arr2.includes(item)
    })
 }
 // similarity([1,2,3], [1,2,4]) -> [1,2]

聯合(union)

const  union = (arr1, arr2) => Array.from(new Set([...arr1, ...arr2]))
    // union([1,2,3], [4,3,2]) -> [1,2,3,4]

排除

支持多參數傳入,利用...剩餘操做符,不修改原數組

const without = (arr, ...args) =>{
        return arr.filter((item) =>{
            return !args.includes(item)
        })
    }
    // without([2, 1, 2, 3], 1, 2) -> [3]

降維/壓縮

...rest參數.根據原始數組中的位置進行分組,多個一維數組,按照原始位置進行合併爲二維數組,空缺的用undefined佔位

const zip = (...arrays) => {
         // 下面的...是擴展操做符,否則數組沒法傳入到Math.max()
         const maxLength = Math.max(...arrays.map((item) => item.length))
         return Array.from({length:maxLength}).map((_, i) =>{
             return Array.from({length: arrays.length},(_, j) =>{
                 return arrays[j][i]
             })
         })
     }
     //zip(['a', 'b'], [1, 2], [true, false]); -> [['a', 1, true], ['b', 2, false]]
     //zip(['a'], [1, 2], [true, false]); -> [['a', 1, true], [undefined, 2, false]]

Browser

頁面底部是否可見

const bottomVisible = () => {
        return document.documentElement.clientHeight + window.scrollY >=  (document.documentElement.scrollHeight || document.documentElement.clientHeight)
    }

偵測設備類型

移動設備/桌面設備

const detectDeviceType = () => {
        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ? "Mobile" : "Desktop";
    }
    // detectDeviceType() -> "Desktop"

元素是否在視窗可見

默認徹底可見,懶加載的時候會用到這個原理

const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
      const { top, left, bottom, right } = el.getBoundingClientRect();
      return partiallyVisible
        ? ((top > 0 && top < window.innerHeight) || (bottom > 0 && bottom < window.innerHeight)) &&
          ((left > 0 && left < window.innerWidth) || (right > 0 && right < window.innerWidth))
        : top >= 0 && left >= 0 && bottom <= window.innerHeight && right <= window.innerWidth;
    };

獲取url查詢參數

const getURLParameters = url =>
        url.match(/([^?=&]+)(=([^&]*))/g).reduce(
            (a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {}
        );

返回頁面頂部

const scrollToTop = () =>{
        const distance = document.documentElement.scrollTop
        if(distance > 0){
            window.requestAnimationFrame(scrollToTop)
            window.scrollTo(0, distance - distance/8)
        }
    }

瀏覽器窗口大小(視窗)

一張網頁的所有面積,就是它的大小。一般狀況下,網頁的大小由內容和CSS樣式表決定。
瀏覽器窗口的大小,則是指在瀏覽器窗口中看到的那部分網頁面積,又叫作viewport(視口)。

注意事項

  • 必須在頁面加載完成後才能運行,不然document對象還沒生成,瀏覽器會報錯
  • clientWidth和clientHeight都是隻讀屬性,不能對它們賦值。
  • window.innerWidth是包括右邊滾動條的寬度的
const getViewport = () =>{
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
        }
    }

網頁大小

若是網頁內容可以在瀏覽器窗口中所有顯示,不出現滾動條,那麼網頁的clientWidth和scrollWidth應該相等。可是實際上,不一樣瀏覽器有不一樣的處理,這兩個值未必相等。因此,咱們須要取它們之中較大的那個值
const getPageArea = () =>{
        return {
            width: Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth),
            height: Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight)
         }
    }

網頁元素絕對位置

指該元素的左上角相對於整張網頁左上角的座標。這個絕對位置要經過計算才能獲得。
  1. 不斷累加offsetParent的offsetTop和offsetLeft屬性

    因爲在表格和iframe中,offsetParent對象未必等於父容器,因此上面的函數對於表格和iframe中的元素不適用。

    function getElementLeft(element){
           var actualLeft = element.offsetLeft;
           var current = element.offsetParent;
       
           while (current !== null){
               actualLeft += current.offsetLeft;
               current = current.offsetParent;
           }
           return actualLeft;
       }
       function getElementTop(element){
           var actualTop = element.offsetTop;
           var current = element.offsetParent;
       
           while (current !== null){
               actualTop += current.offsetTop;
               current = current.offsetParent;
           }
           return actualTop;
       }
  2. 利用getBoundingClientRect方法

    此方法其中包含了left、right、top、bottom四個屬性,分別對應了該元素的左上角和右下角相對於瀏覽器窗口(viewport)左上角的距離.(其實也就是網頁元素的相對位置)

     var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;
       
        var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;

網頁元素相對位置

網頁元素的相對位置,指該元素左上角相對於瀏覽器窗口左上角的座標。

有了絕對位置之後,得到相對位置就很容易了,只要將絕對座標減去頁面的滾動條滾動的距離就能夠了 也就是減去document.documentElement.scrollLeft|scrollTop

//快捷方法
    var X= this.getBoundingClientRect().left;
    
   var Y =this.getBoundingClientRect().top;

滾動位置

返回當前頁面的滾動位置。請使用pageXOffset和pageYOffset, 若是已定義,不然使用scrollLeft和scrollTop。你能夠省略el來使用窗口的默認值。pageXOffset是scrollY的別名(event.pageX是鼠標活動事件的屬性)

const getScrollPosition = (el = window) =>{
        return ({x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft, y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop});
    }
      
    // getScrollPosition() -> {x: 0, y: 200}

Function

鏈式異步調用(chainAsync)

循環遍歷包含異步事件的函數數組,每次異步事件完成後再調用

const chainAsync = fns =>{
        let curr = 0
        const next = () =>{
            fns[curr++](next)
        }
        next()
    }
    /*
    chainAsync([
        next => { console.log('0 seconds'); setTimeout(next, 1000); },
        next => { console.log('1 second');  setTimeout(next, 1000); },
        next => { console.log('2 seconds'); }
    ])
    */

組合

執行從右到左的函數功能組合

使用Array.reduce()來執行從右到左的函數組合。最後(最右邊的)函數能夠接受一個或多個參數;其他的函數參數必須是一元的.

const compose = (...fns) => {
        return fns.reduce((f,g) => {
            //...args 剩餘參數, args是數組,再轉換爲函數參數
            return (...args) => f(g(...args))
        })
    }
    /*
    const add5 = x => x + 5
    const multiply = (x, y) => x * y
    const multiplyAndAdd5 = compose(add5, multiply)
    multiplyAndAdd5(5, 2) -> 15
    */

管道

執行從左到右的函數功能組合

使用Array.reduce()和spread運算符(...)來執行從左到右的函數組合。第一個(最左邊的)函數能夠接受一個或多個參數;其他的功能必須是一元的。

const pipeFunctions  = (...fns) => {
       return fns.reduce((f,g) => {
           //...args 剩餘參數, args是數組,再轉換爲函數參數
           return (...args) => g(f(...args))
       })
   }
    /*
    
    */

鏈式調用promise

使用Array.reduce()建立一個promise鏈,每一個promise在解析後返回下一個promise

const promiseSeries = ps => {
        return ps.reduce((p, next) => {
            return p.then(next)
          }, Promise.resolve())
    }
    // const delay = (d) => new Promise(r => setTimeout(r, d))
    // runPromisesInSeries([() => delay(1000), () => delay(2000)]) -> executes each promise sequentially, taking a total of 3 seconds to complete

睡眠(sleep)

延遲異步函數的執行,延遲執行異步函數的一部分,經過把它放到睡眠狀態,返回一個Promise。

const sleep = ms => {
        return new Promise((resolve,reject) => {
            setTimeout(resolve, ms)
        })
    }
    /*
    async function sleepyWork() {
      console.log('I\'m going to sleep for 1 second.');
      await sleep(1000);
      console.log('I woke up after 1 second.');
    }
    */

Math

數組總和

const arraySum = arr => {
        return arr.reduce((acc,curr) => {
            return acc + curr
        },0)
    }

數組平均數

const arrayAverage = arr => {
        return arr.reduce((acc,curr) => {
            return acc + curr
        },0) / arr.length
    }

數字數組化

const digitize = number =>{
        return [...number.toString()]
        // return [...''+number]
    }
    // digitize(2334) -> [2, 3, 3, 4]

階乘(factorial)

// 一個函數內處理的結果可使用return 返回,這樣在調用函數的地方就能夠用變量接收返回
       結果
    const factorial = n =>{
        // 不return的話那就不會返回這個數值 默認返回的是undefined
        return n <= 1 ? 1 : n * factorial(n-1)
    }
    // factorial(6) -> 720

斐波那契數列(fibonacci)

const fibonacci = n =>{
        return Array(n).fill(0).reduce((acc, val, i) =>{
            return acc.concat(i >1 ? acc[i -1] + acc[i -2] : i) 
        }, [])
    }
    // fibonacci(5) -> [0,1,1,2,3]

判斷素數

const isPrime = num =>{
        for (var  i = 2; i < num; i++) {
            if (num % i ===0){
                return false
            }
        }
        return num >= 2;
    }
    // isPrime(11) -> true
    // isPrime(12) -> false
    // isPrime(1) -> false

判斷迴文

const palindrome = str =>{
        const s = str.toLowerCase().replace(/[\w_]/g, '')
        return s === s.split("").reverse().join('')
    }
    // palindrome('taco cat') -> true

指定範圍隨機整數

const randomIntegerRange = (min, max) =>{
        return Math.floor(Math.random()* (max - min +1)) + min
    }
    //randomIntegerRange (1, 10) -> 5

四捨五入到指定小數位

const roundx = (n, decimals=0) => {
      return Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)
    }
    // roundx(1.005, 2) -> 1.01
    const roundx = (n, decimals=0) =>{
        return n.toFixed(decimals)
    }
    // roundx(1.2, 3)  -> "1.200"

數組標準差

const standardDeviation = (arr, usePopulation = false) => {
      const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length;
      return Math.sqrt(
        arr.reduce((acc, val) => acc.concat(Math.pow(val - mean, 2)), [])
           .reduce((acc, val) => acc + val, 0) / (arr.length - (usePopulation ? 0 : 1))
      );
    };
    // standardDeviation([10,2,38,23,38,23,21]) -> 13.284434142114991 (sample)

Media

語言轉文字(讀取文字)

瞭解有關Web Speech API的SpeechSynthesisUtterance接口的更多信息。

const speechSynthesis = message => {
      const msg = new SpeechSynthesisUtterance(message);
      msg.voice = window.speechSynthesis.getVoices()[0];
      window.speechSynthesis.speak(msg);
    };
    // speechSynthesis('Hello, World') -> plays the message

Object

給定數組建立對象

const objectFromPairs =  arr => {
        return arr.reduce((acc, val) =>{
            acc[val[0]] = val[1]
            return acc
            // return (acc[val[0]] = val[1], acc)
        },{})
    }
    // objectFromPairs([['a',1],['b',2]]) -> {a: 1, b: 2}

給定對象建立數組

const objectToPairs = obj =>{
        return Object.keys(obj).map((key) =>{
            return [key, obj[key]]
        })
    }
    // objectToPairs({a: 1, b: 2}) -> [['a',1],['b',2]])

對象深度選擇(select)

能夠避免深度對象選擇不到時的報錯?

const select = (from, selector) =>{
        return selector.split('.').reduce((prev,cur) =>{
            return prev && prev[cur]
        },from)
    }
     // const obj = {selector: {to: {val: 'val to select'}}};
     // select(obj, 'selector.to.val'); -> 'val to select'

對象組是否都含有給定的屬性

const truthCheckCollection = (collection, key) =>{
        return collection.every((obj => {
            return obj[key]
        }))
    }
    // truthCheckCollection([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}], "sex") -> true

String

首字母大寫(capitalize)

const capitalize = ([first, ...rest]) =>{
        return first.toUpperCase() + rest.join('')
    }
   // capitalize('myName') -> 'MyName'

首字母大寫每一個單詞

const capitalizeEveryWord = str =>{
        // 匹配的單詞
        return str.replace(/\b[a-z]/g, char =>{
            return char.toUpperCase()
        })
    }

元音字符數

const countVowels = str => {
        // 匹配不到時返回null 因此用[]避免報錯
        return (str.match(/[aeiou]/ig) || []).length
    }

轉義字符串

轉義字符串以在正則表達式中使用。 使用replace()來轉義特殊字符。

const escapeRegExp = str =>{
        return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    }

轉換駝峯字符串

將駝峯形式的字符串轉換爲指定字符分割的形式

const fromCamelCase = (str, separator = '_') =>{
        return str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2').replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase()
    }
    // fromCamelCase('someDatabaseFieldName', ' ') -> 'some database field name'
    // fromCamelCase('someLabelThatNeedsToBeCamelized', '-') -> 'some-label-that-needs-to-be-camelized'
    // fromCamelCase('someJavascriptProperty', '_') -> 'some_javascript_property'

轉換左右

const reverseString = str =>{
        return str.split('').reverse().join('')
    }
    // reverseString('foobar') -> 'raboof'

按照字母排序

const sortCharactersInString = str =>{
       return  str.split('').sort((a, b) => {
           return a.localeCompare(b)
       }).join('');
    }
    // sortCharactersInString('cabbage') -> 'aabbceg'

轉爲駝峯

使用replace()去除下劃線,連字符和空格,並將單詞轉換爲camelcase。

const toCamelCase = str =>{
        return str.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2, offset) =>{
           return p2 ? p2.toUpperCase() : p1.toLowerCase()
        })
    }
    // toCamelCase("some_database_field_name") -> 'someDatabaseFieldName'
    // toCamelCase("Some label that needs to be camelized") -> 'someLabelThatNeedsToBeCamelized'
    // toCamelCase("some-javascript-property") -> 'someJavascriptProperty'
    // toCamelCase("some-mixed_string with spaces_underscores-and-hyphens") -> 'someMixedStringWithSpacesUnderscoresAndHyphens'

轉爲單詞數組

使用String.split()與提供的模式(默認爲非alpha做爲正則表達式)來轉換爲字符串數組。使用Array.filter()刪除任何空字符串。

const words = (str, pattrern = /[^a-zA-Z-]+/) =>{
        return str.split(pattrern).filter(Boolean)
    }
   
    // ["I", "love", "javaScript", ""]
    // words("I love javaScript!!") -> ["I", "love", "javaScript"]
    // ["python", "javaScript", "coffee"]
    // words("python, javaScript & coffee") -> ["python", "javaScript", "coffee"]

## Utility
### 擴展Hex(16進制顏色)
將3位數的顏色代碼擴展爲6位數的顏色代碼

const extendHex = shortHex => {
       return '#' + shortHex.slice(shortHex.startsWith('#') ? 1 : 0).split('').map( s => s+s).join("")
   }

值的類型

const getType = v =>{
        v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase()
    }   
    // getType(new Set([1,2,3])) -> "set"

十六進制顏色轉rgb

若是提供了alpha值,則將顏色代碼轉換爲rgb()或rgba()字符串。 使用&(和)運算符,按位右移運算符和掩碼位將具備RGB值的十六進制顏色代碼(帶或不帶前綴#)轉換爲字符串。若是是3位數的顏色代碼,則先轉換爲6位數字版本。若是一個alpha值和6位十六進制一塊兒提供,則返回rgba()字符串。

const hexToRGB = hex => {
      let alpha = false, h = hex.slice(hex.startsWith('#') ? 1 : 0);
      if (h.length === 3) h = [...h].map(x => x + x).join('');
      else if (h.length === 8) alpha = true;
      h = parseInt(h, 16);
      return 'rgb' + (alpha ? 'a' : '') + '('
        + (h >>> (alpha ? 24 : 16)) + ', '
        + ((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) + ', '
        + ((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0))
        + (alpha ? `, ${(h & 0x000000ff)}` : '') + ')';
    };

    // hexToRGB('#27ae60ff') -> 'rgba(39, 174, 96, 255)'
    // hexToRGB('27ae60') -> 'rgb(39, 174, 96)'
    // hexToRGB('#fff') -> 'rgb(255, 255, 255)'

### 隨機十六進制顏色
使用Math.random生成一個隨機的24位(6x4bits)十六進制數字。使用位移,而後使用toString(16)將其轉換爲十六進制字符串。

const randomHexColorCode = () =>{
       return '#'+(Math.random()*0xFFFFFF<<0).toString(16);
   } 
   // randomHexColorCode() -> "#e34155"
   // randomHexColorCode() -> "#fd73a6"
   // randomHexColorCode() -> "#4144c6"

rgb轉hex顏色

將RGB的值轉換爲顏色代碼。 使用按位左移運算符(<<)和toString(16),而後padStart(6,「0」)將給定的RGB參數轉換爲十六進制字符串以得到6位十六進制值。

const RGBToHex = (r, g, b) => {
        return ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
    }
    // RGBToHex(255, 165, 1) -> 'ffa501'

UUID生成器

使用crypto API生成符合RFC4122版本4的UUID。

const UUIDGenerator = () =>
      ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
        (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
      );
    // UUIDGenerator() -> '7982fcfe-5721-4632-bede-6000885be57d'
相關文章
相關標籤/搜索