天天看點

前端常用JS操作與js特性了解——《前端那些事》

01、 取出兩個數組相同的值、不同值

相同值

let arr1 =[1,3,5,7,9];
let arr2 = [1,2,3,4,5,6,7];
let arr3 = arr1.filter(item => arr2 .indexOf(item) > -1) ; // [1, 3, 5, 7]           

不同值

let arr1 =[1,3,5,7,9];
let arr2 = [1,2,3,4,5,6,7];
function getArrDifference(arr1, arr2) {
    return arr1.concat(arr2).filter(function(item, i, arr) {
        return arr.indexOf(item) === arr.lastIndexOf(item);
   });
}
let arr3 =getArrDifference(arr1,arr12);  // [9, 2, 4, 6]           

02、 數組交集/并集/差集

let a = [1, 2, 3]
let b = [2, 4, 5]

// 并集
let union = a.concat(b.filter((v) => !a.includes(v)))
// [1,2,3,4,5]

// 交集
let intersection = a.filter((v) => b.includes(v))
// [2]

// 差集
let difference = a.concat(b).filter((v) => !a.includes(v) || !b.includes(v))
// [1,3,4,5]
           

03、判斷資料類型

Object.prototype.toString.call()           

04、 時間戳轉時間 yyyy-mm-dd hh:mm:ss

function getyyyyMMdd(data){
    var d = new Date(data*1000);
    var curr_date = d.getDate();
    var curr_month = d.getMonth() + 1;
    var curr_year = d.getFullYear();
    var curr_hour = d.getHours();;
    var curr_minute = d.getMinutes();
    var curr_second = d.getSeconds();
    String(curr_month).length < 2 ? (curr_month = "0" + curr_month): curr_month;
    String(curr_date).length < 2 ? (curr_date = "0" + curr_date): curr_date;
    String(curr_hour).length < 2 ? (curr_hour = "0" + curr_hour): curr_hour;
    String(curr_minute).length < 2 ? (curr_minute = "0" + curr_minute): curr_minute;
    String(curr_second).length < 2 ? (curr_second = "0" + curr_second): curr_second;
    yyyyMMdd = curr_year + "-" + curr_month +"-"+ curr_date+"  "+curr_hour+":"+curr_minute+":"+curr_second;
   return yyyyMMdd;
}           

05、 擷取近7天時間

const arr=[] 
for (let i = 0; i < 7; i++) {
        const time = new Date(new Date().setDate(new Date().getDate() + i - 7));
        const year = time.getFullYear();
        const month = `0${time.getMonth() + 1}`.slice(-2);
        const strDate = `0${time.getDate()}`.slice(-2);
        arr.push(`${year}-${month}-${strDate}`);
   }
           

06、 整數變量交換

1

let a = 10;
let b = 50;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(a, b); // 50 10

2

var a = 2;
var b = 4;
a = a + b;
b = a - b;
a = a - b;
console.log(a, b); // 4 2

3

let a = 10;
let b = 50;
[a,b]=[b,a]
console.log(a);// 50
console.log(b)// 10           

07、 數組去重多重方式

  1. Set(最常用)
Array.prototype.unique = function() {
    return [...new Set(this)];
}
var array = [1, 2, 3, 43, 45, 1, 2, 2, 4, 5];
array.unique(); //[1, 2, 3, 43, 45, 4, 5]

2. Map

Array.prototype.unique = function() {
    const tmp = new Map();
    return this.filter(item => {
        return !tmp.has(item) && tmp.set(item, 1);
    })
}
var array = [1, 2, 3, 43, 45, 1, 2, 2, 4, 5];
array.unique(); //[1, 2, 3, 43, 45, 4, 5]

3. Array.prototype.indexOf()

Array.prototype.unique = function() {
    return this.filter((item, index) => {
        return this.indexOf(item) === index;
    })
}
var array = [1, 2, 3, 43, 45, 1, 2, 2, 4, 5];
array.unique(); //[1, 2, 3, 43, 45, 4, 5]

4.Array.prototype.includes()

Array.prototype.unique = function() {
    const newArray = [];
    this.forEach(item => {
        if (!newArray.includes(item)) {
            newArray.push(item);
        }
    });
    return newArray;
}
var array = [1, 2, 3, 43, 45, 1, 2, 2, 4, 5];
array.unique(); //[1, 2, 3, 43, 45, 4, 5]

5. Array.prototype.reduce()

Array.prototype.unique = function() {
    return this.sort().reduce((init, current) => {
        if (init.length === 0 || init[init.length - 1] !== current) {
            init.push(current);
        }
        return init;
    }, []);
}
var array = [1, 2, 3, 43, 45, 1, 2, 2, 4, 5];
array.unique(); //[1, 2, 3, 43, 45, 4, 5]           

08、 判斷小數是否相等

console.log(0.1 + 0.2  === 0.3); // false

function equal(number1, number2) {
    return Math.abs(number1 - number2) < Math.pow(2, -52);
}
console.log(equal(0.1 + 0.2, 0.3)); //true           

09、 多元數組降次元

二維數組

let arr = [ [1], [2], [3] ];
arr = Array.prototype.concat.apply([], arr);
console.log(arr);// [1, 2, 3]

let array = [ [1], [2], [3] ];
array = array.flat(2);  //es6 新增
console.log(array); // [1, 2, 3]           

多元數組

1. 調用ES6中的flat方法

let arrMore = [1, 2, [3], [[4]]];
arr= arrMore.flat(Infinity);  //使用 Infinity 作為深度,展開任意深度的嵌套數組
console.log(arr); // [1,2,3,4]

2. replace + split

let arrMore = [1, 2, [3], [[4]]];
let str = JSON.stringify(arrMore);
arr= str.replace(/(\[|\])/g, '').split(',');

3. replace + JSON.parse

let arrMore = [1, 2, [3], [[4]]];
let str = JSON.stringify(arrMore);
str = str.replace(/(\[|\]))/g, '');
str = '[' + str + ']';
arr= JSON.parse(str);

4. 普通遞歸

let ary= [1, 2, [3], [[4]]];
let result = [];
let fn = function(ary) {
  for(let i = 0; i < ary.length; i++) {
    let item = ary[i];
    if (Array.isArray(ary[i])){
      fn(item);
    } else {
      result.push(item);
    }
  }
}

5. 利用reduce函數疊代

function flatten(ary) {
    return ary.reduce((pre, cur) => {
        return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
    }, []);
}
let ary= [1, 2, [3], [[4]]];
console.log(flatten(ary))

6. 擴充運算符

//隻要有一個元素有數組,那麼循環繼續
while (ary.some(Array.isArray())) {
  ary = [].concat(...ary);
}           

010、 快速浮點數轉整數

console.log(10.9 | 0);  // 10
console.log(-10.9 | 0);// 10

console.log(~~10.9); // 10
console.log(~~-10.9); // 10           

11、 函數防抖 函數節流

函數防抖:在 n 秒内重新觸發,會重新開始計算時間
實作:通過 setTimeout 和 clearTimeout 實作
應用場景:按鈕點選事件/input事件,防止使用者多次重複送出

//簡易寫法
let timeout;
$(".xx").click(function() {
    clearTimeout(timeout)    
    timeout = setTimeout(() => {
        //在此處寫調用的方法,可以實作僅最後一次操作生效
  }, 1000)
    
})


function debounce (fn, time) {
  let timer = null
  // 閉包
  return () => {
    // 每次都會重新開始計算時間
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn()
    }, time)
  }
}

function sayDebounce() {
  console.log('我是防抖,每次觸發我都會重新計算一次時間')
}

btn.onclick = debounce(sayDebounce, 1000);
//或$("#btn").on('click', debounce(confirmExchange, 1000))





函數節流:在 n 秒中隻執行一次
實作:通過 setTimeout 執行
應用場景:
- 滑鼠/觸摸屏的mouseover/touchmove事件
- 頁面視窗的resize事件
- 滾動條的scroll事件

// 初步實作
const throttle = function (fn, time) {
  let canRun = true
  // 閉包
  return () => {
    if (canRun) {
      canRun = false
      setTimeout(() => {
        canRun = true
        fn()
      }, time)
    }
  }
}

function sayThrottle() {
  console.log('我是節流,我在固定的時間内執行一次')
}
window.onscroll = throttle(sayThrottle, 1000)

差別:一定時間内任務執行的次數。比如一個事件每1s觸發很多次,平均每10ms觸發一次。節流,假設時間間隔為100ms,在100ms内隻能執行一次事件回調函數,1s内函數的調用次數為:1000 /100 = 10次防抖,假設時間間隔為100ms,時間觸發的間隔必須要大于100ms,才調用回調函數。因為觸發間隔=10ms < 100ms,1s内函數的調用次數為:0;           

12、 按需置頂數組元素

//置頂數組中flag為1的元素
let data = [
        { id: 1, flag: 0 },
        { id: 2, flag: 0 },
        { id: 3, flag: 0 },
        { id: 4, flag: 1 },
        { id: 5, flag: 0 },
        { id: 6, flag: 0 }
      ];
      data.map((item, index) => {
        if (item.flag == 1) {
         data.unshift(data.splice(index, 1)[0]);
        }
      });
      console.log(data);           

13、閉包了解

閉包是指有權通路另一個函數作用域中的變量的函數,個人認為閉包最大的用處就是防止對全局作用域的污染。 試想如果我們把一些僅僅隻用到一兩次的變量都聲明在全局作用域中,最後肯定是容易出錯且不可維護的。而閉包最神奇的地方就是能在一個函數外通路函數中的局部變量,把這些變量用閉包的形式放在函數中便能避免污染。
一、閉包是什麼?
《JavaScript進階程式設計》中寫道:“閉包是指有權通路另一個函數作用域中的變量的函數”,如果用下定義的觀點看,這句話就是說“閉包是函數”,我帶着懷疑的心态又去網上找了找,發現什麼說法都有,終究沒能明白閉包的含義,還是看代碼來得直接。

function outter()

{

var sky="blue";

function inner()

{console.log(sky); 

 }

return inner;}

var result=outter();

result();//"blue"

這段代碼就包含一個簡單的閉包:outter函數的傳回值是一個函數,即inner。inner在outter内部,理所當然能通路到局部變量sky,但當inner作為outter的傳回值賦給outter外的全局變量時,神奇的事情發生了:在全局作用域中通路到了sky,這就是閉包。

二、閉包的原理?


每個函數都有自己的執行環境,當一個函數被執行時,它的執行環境就會被推入環境棧,其活動對象(存儲環境中定義的變量及函數)加入作用域鍊中,一旦函數執行完,棧将其環境彈出,活動對象被銷毀。·

對于上面的例子來說,outter執行完之後将傳回inner給了result,outter的執行環境從環境棧彈出,控制權交給全局環境,outter的活動對象理應被銷毀。但此時inner已經存儲在全局活動對象中了,同時inner需要通路sky,是以outter的活動對象沒有被銷毀,即使result執行完畢,outter的活動對象依然存在于作用域鍊中,隻有當result被銷毀

result= null;

outter的活動對象才會徹底釋放。

三、閉包有什麼用?
說了這麼多,閉包到底有什麼用呢?我個人認為閉包最大的用處就是防止對全局作用域的污染。 試想如果我們把一些僅僅隻用到一兩次的變量都聲明在全局作用域中,最後肯定是容易出錯且不可維護的。而閉包最神奇的地方就是能在一個函數外通路函數中的局部變量,把這些變量用閉包的形式放在函數中便能避免污染。           

繼續閱讀