前端常用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的活动对象才会彻底释放。

三、闭包有什么用?
说了这么多,闭包到底有什么用呢?我个人认为闭包最大的用处就是防止对全局作用域的污染。 试想如果我们把一些仅仅只用到一两次的变量都声明在全局作用域中,最后肯定是容易出错且不可维护的。而闭包最神奇的地方就是能在一个函数外访问函数中的局部变量,把这些变量用闭包的形式放在函数中便能避免污染。
上一篇:艾伟也谈项目管理,只有好代码的项目能成功吗?


下一篇:Android 文件下载和AsyncTask异步线程下载操作