作者:火狼https://cloud.tencent.com/developer/article/1666138

JS是前端的核心,但有些使用技巧你还不一定知道;
本文梳理了JS的41个技巧,帮助大家提高JS的使用技巧;
文章有点长,可以clone下源码,直接撸,源码地址 https://github.com/lanzhsh/react-vue-koa/tree/master/js/skill,原创不易,欢迎star;

Array

1.数组交集

普通数组

const arr1 = [1, 2, 3, 4, 5 , 8 ,9],arr2 = [5, 6, 7, 8, 9];

const intersection = arr1.filter(function (val) { return arr2.indexOf(val) > -1 })console.log(intersection) //[5, 8, 9]复制代码

数组对象
数组对象目前仅针对value值为简单的Number,String,Boolan数据类型 文中JSON.stringif比较对象是简写方法,完整的对象比较请看技巧24.对象是否相等

const arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }, { name: 'name5', id: 5 }];const arr2 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }];const result = arr2.filter(function (v) {  return arr1.some(n => JSON.stringify(n) === JSON.stringify(v))})console.log(result); // [{ name: 'name1', id: 1 },{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name5', id: 5 }]复制代码

2.数组并集

普通数组

const arr1 = [1, 2, 3, 4, 5, 8, 9]const arr2 = [5, 6, 7, 8, 9];const result = arr1.concat(arr2.filter(v => !arr1.includes(v)))console.log(result) //[1, 2, 3, 4, 5, 8, 9, 6, 7]复制代码

数组对象

const arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }];const arr2 = [{ name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }];let arr3 = arr1.concat(arr2);let result = [];let obj = [];result = arr3.reduce(function (prev, cur, index, arr) {  obj[cur.id] ? '' : obj[cur.id] = true && prev.push(cur);  return prev;}, []);console.log(result); //[{ name: 'name1', id: 1 },{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name4', id: 4 },{ name: 'name5', id: 5 }]复制代码

3.数组差集

数组arr1相对于arr2所没有的
普通数组

const arr1 = [1, 2, 3, 4, 5, 8, 9]const arr2 = [5, 6, 7, 8, 9];const diff = arr1.filter(item => !new Set(arr2).has(item))console.log(diff) //[ 1, 2, 3, 4 ]复制代码

数组对象

// 对象数组let arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }];let arr2 = [{ name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }];let result = arr1.filter(function (v) {  return arr2.every(n => JSON.stringify(n) !== JSON.stringify(v))})console.log(result); // [ { name: 'name2', id: 2 }, { name: 'name3', id: 3 } ]复制代码

4.数组补集

两个数组各自没有的集合
普通数组

const arr1 = [1, 2, 3, 4, 5, 8, 9]const arr2 = [5, 6, 7, 8, 9];const difference = Array.from(new Set(arr1.concat(arr2).filter(v => !new Set(arr1).has(v) || !new Set(arr2).has(v)))) console.log(difference) //[ 1, 2, 3, 4, 6, 7 ]复制代码

数组对象

let arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }];let arr2 = [{ name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }];let arr3 = arr1.concat(arr2);let result = arr3.filter(function (v) {  return arr1.every(n => JSON.stringify(n) !== JSON.stringify(v)) || arr2.every(n => JSON.stringify(n) !== JSON.stringify(v))})console.log(result); // [{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name4', id: 4 },{ name: 'name5', id: 5 }]复制代码

总结一下,差集就是数组arr1相对于arr2所没有的集合,补集是两个数组各自没有的集合

5.数组去重

普通数组

console.log(Array.from(new Set([1, 2, 3, 3, 4, 4]))) //[1,2,3,4]console.log([...new Set([1, 2, 3, 3, 4, 4])]) //[1,2,3,4]复制代码

数组对象

const arr = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }, { name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }]; const result = []; arr.forEach(item=>{    !result.some(v => JSON.stringify(v) === JSON.stringify(item)) && result.push(item) }) console.log(result) //[{ name: 'name1', id: 1 },{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name4', id: 4 },{ name: 'name5', id: 5 }]复制代码

6.数组排序

普通数组

console.log([1, 2, 3, 4].sort((a, b) => a - b)); // [1, 2,3,4] 升序console.log([1, 2, 3, 4].sort((a, b) => b - a)); // [4,3,2,1] 降序复制代码

数组对象

const arr1 = [{ name: "Rom", age: 12 }, { name: "Bob", age: 22 }].sort((a, b) => { return a.age - b.age })//升序const arr2 = [{ name: "Rom", age: 12 }, { name: "Bob", age: 22 }].sort((a, b) => { return -a.age + b.age })//降序console.log(arr2) // [{ name: 'Bob', age:22 }, { name: 'Rom', age: 12 }]console.log(arr1) // [ { name: 'Rom', age: 12 }, { name: 'Bob', age: 22 } ]复制代码

两个种类型数组都可以使用sort排序,sort是浏览器内置方法;
默认是升序排序,默认返回一个函数,有两个参数:
(a, b) => a - b 是升序;
(a, b) => b - a 是降序。

7.最大值

普通数组

Math.max(...[1, 2, 3, 4]) //4Math.max.apply(this, [1, 2, 3, 4]) //4[1, 2, 3, 4].reduce((prev, cur, curIndex, arr) => {   return Math.max(prev, cur);}, 0) //4复制代码

取数组对象中id的最大值

const arr = [{ id: 1, name: 'jack' },{ id: 2, name: 'may' },{ id: 3, name: 'shawn' },{ id: 4, name: 'tony' }]const arr1 = Math.max.apply(Math, arr.map(item => { return item.id }))const arr2 = arr.sort((a, b) => { return b.id - a.id })[0].idconsole.log(arr1) // 4console.log(arr2) // 4复制代码

8.数组求和

普通数组

[1, 2, 3, 4].reduce(function (prev, cur) {  return prev + cur;}, 0) //10 复制代码

数组对象

const sum = [{age:1},{age:2}].reduce(function (prev, cur) {  return prev + cur.age;}, 0) //3console.log(sum)复制代码

9.数组合并

普通数组

const arr1 =[1, 2, 3, 4].concat([5, 6]) //[1,2,3,4,5,6]const arr2 =[...[1, 2, 3, 4],...[4, 5]] //[1,2,3,4,5,6]const arrA = [1, 2], arrB = [3, 4]const arr3 =[].concat.apply(arrA, arrB)//arrA值为[1,2,3,4]复制代码

数组对象

const arr4 = [{ age: 1 }].concat([{ age: 2 }])const arr5 = [...[{ age: 1 }],...[{ age: 2 }]]console.log(arr4) //[ { age: 1 }, { age: 2 } ]console.log(arr5) // [ { age: 1 }, { age: 2 } ]复制代码

10.数组是否包含值

普通数组

console.log([1, 2, 3].includes(4)) //falseconsole.log([1, 2, 3].indexOf(4)) //-1 如果存在换回索引console.log([1, 2, 3].find((item) => item === 3)) //3 如果数组中无值返回undefinedconsole.log([1, 2, 3].findIndex((item) => item === 3)) //2 如果数组中无值返回-1复制代码

数组对象

const flag = [{age:1},{age:2}].some(v=>JSON.stringify(v)===JSON.stringify({age:2}))console.log(flag)复制代码

11.数组每一项都满足

普通数组

[1, 2, 3].every(item => { return item > 2 })复制代码

数组对象

const arr = [{ age: 3 }, { age: 4 }, { age: 5 }]arr.every(item => { return item.age > 2 }) // true复制代码

12.数组有一项满足

普通数组

[1, 2, 3].some(item => { return item > 2 })复制代码

数组对象

const arr = [{ age: 3 }, { age: 4 }, { age: 5 }]arr.some(item => { return item.age true复制代码

13.版本号排序

方法一

function sortNumber(a, b) {  return a - b}const b = [1,2,3,7,5,6]const a = ["1.5", "1.5", "1.40", "1.25", "1.1000", "1.1"];

console.log(a.sort(sortNumber)); // [ 1, 2, 3, 5, 6, 7 ]console.log(b.sort(sortNumber)); //[ '1.1000', '1.1', '1.25', '1.40', '1.5', '1.5' ]复制代码

可见sort排序对整数可以,类似版本号这个格式就不适用了,因为sort函数在比较字符串的时候,是比较字符串的Unicode进行排序的。

方法二

//假定字符串的每节数都在5位以下//去除数组空值||空格if (!Array.prototype.trim) {  Array.prototype.trim = function () {    let arr = []; this.forEach(function (e) {      if (e.match(/\S+/)) arr.push(e);    })    return arr;  }}

//提取数字部分function toNum(a) {  let d = a.toString();  let c = d.split(/\D/).trim();  let num_place = ["", "0", "00", "000", "0000"], r = num_place.reverse();  for (let i = 0; i     let len = c[i].length;    c[i] = r[len] + c[i];  }  let res = c.join('');  return res;}

//提取字符function toChar(a) {  let d = a.toString();  let c = d.split(/\.|\d/).join('');  return c;}

function sortVersions(a, b) {

  let _a1 = toNum(a), _b1 = toNum(b);  if (_a1 !== _b1) return _a1 - _b1;  else {    _a2 = toChar(a).charCodeAt(0).toString(16);    _b2 = toChar(b).charCodeAt(0).toString(16);    return _a2 - _b2;  }}

let arr1 = ["10", "5", "40", "25", "1000", "1"];let arr2 = ["1.10", "1.5", "1.40", "1.25", "1.1000", "1.1"];let arr3 = ["1.10c", "1.10b", "1.10C", "1.25", "1.1000", "1.10A"];console.log(arr1.sort(sortVersions)) //[ '1', '5', '10', '25', '40', '1000' ]console.log(arr2.sort(sortVersions)) //[ '1.1', '1.5', '1.10', '1.25', '1.40', '1.1000' ]console.log(arr3.sort(sortVersions)) // [ '1.10A', '1.10C', '1.10b', '1.10c', '1.25', '1.1000' ]

复制代码

可以看出这个函数均兼容整数,非整数,字母;
字母排序是根据Unicode排序的,所以1.10b在1.10C的后面

14. 对象转数组

将数组的key和value转化成数组

Object.keys({ name: '张三', age: 14 }) //['name','age']Object.values({ name: '张三', age: 14 }) //['张三',14]Object.entries({ name: '张三', age: 14 }) //[[name,'张三'],[age,14]]Object.fromEntries([name, '张三'], [age, 14]) //ES10的api,Chrome不支持 , firebox输出{name:'张三',age:14}复制代码

15.数组转对象

将数组的值转化为对象的value

const arrName = ['张三', '李四', '王五']const arrAge=['20','30','40']const arrDec = ['描述1', '描述2', '描述3']const obj = arrName.map((item,index)=>{  return { name: item, age: arrAge[index],dec:arrDec[index]}})

console.log(obj) // [{ name: '张三', age: '20', dec: '描述1' },{ name: '李四', age: '30', dec: '描述2' },{ name: '王五', age: '40', dec: '描述3' }]复制代码

16.数组解构

const arr=[1,2]; //后面一定要加分号,因为不加解释器会认为在读数组[arr[1], arr[0]] = [arr[0], arr[1]]; // [2,1]复制代码

Object

17.对象变量属性

const flag = true;const obj = {    a: 0,    [flag ? "c" : "d"]: 2};// obj => { a: 0, c: 2 }复制代码

18.对象多余属性删除

const { name, age, ...obj } = { name: '张三', age: 13, dec: '描述1', info: '信息' }console.log(name)  // 张三console.log(age)  // 13console.log(obj)  // {dec: '描述1', info: '信息' }复制代码

19.对象嵌套属性解构

const { info:{ dec} } = { name: '张三', age: 13, info:{dec: '描述1', info: '信息' }}console.log(dec) // 描述1复制代码

20.解构对象属性别名

const { name:newName } = { name: '张三', age: 13 }console.log(newName)  // 张三复制代码

21.解构对象属性默认值

const { dec='这是默认dec值' } = { name: '张三', age: 13 }console.log(dec) //这是默认dec值复制代码

22.拦截对象

利用Object.defineProperty拦截对象
无法拦截数组的值

let obj = { name: '', age: '', sex: '' },  defaultName = ["这是姓名默认值1", "这是年龄默认值1", "这是性别默认值1"];Object.keys(obj).forEach(key => {  Object.defineProperty(obj, key, { // 拦截整个object 对象,并通过get获取值,set设置值,vue 2.x的核心就是这个来监听    get() {      return defaultName;    },    set(value) {      defaultName = value;    }  });});

console.log(obj.name); // [ '这是姓名默认值1', '这是年龄默认值1', '这是性别默认值1' ]console.log(obj.age); // [ '这是姓名默认值1', '这是年龄默认值1', '这是性别默认值1' ]console.log(obj.sex); // [ '这是姓名默认值1', '这是年龄默认值1', '这是性别默认值1' ]obj.name = "这是改变值1";console.log(obj.name); // 这是改变值1console.log(obj.age);  // 这是改变值1console.log(obj.sex); // 这是改变值1

let objOne = {}, defaultNameOne = "这是默认值2";Object.defineProperty(obj, 'name', {  get() {    return defaultNameOne;  },  set(value) {    defaultNameOne = value;  }});console.log(objOne.name); // undefinedobjOne.name = "这是改变值2";console.log(objOne.name); // 这是改变值2复制代码

利用proxy拦截对象

let obj = { name: '', age: '', sex: '' }let handler = {  get(target, key, receiver) {    console.log("get", key);     return Reflect.get(target, key, receiver);  },  set(target, key, value, receiver) {    console.log("set", key, value); // set name 李四  // set age 24    return Reflect.set(target, key, value, receiver);  }};let proxy = new Proxy(obj, handler);proxy.name = "李四";proxy.age = 24;复制代码

defineProterty和proxy的对比:
1.defineProterty是es5的标准,proxy是es6的标准;
2.proxy可以监听到数组索引赋值,改变数组长度的变化;
3.proxy是监听对象,不用深层遍历,defineProterty是监听属性;
4.利用defineProterty实现双向数据绑定(vue2.x采用的核心)

23.对象深度拷贝

JSON.stringify深度克隆对象;
1.无法对函数 、RegExp等特殊对象的克隆;
2.会抛弃对象的constructor,所有的构造函数会指向Object;
3.对象有循环引用,会报错

const mapTag = '[object Map]';const setTag = '[object Set]';const arrayTag = '[object Array]';const objectTag = '[object Object]';const argsTag = '[object Arguments]';

const boolTag = '[object Boolean]';const dateTag = '[object Date]';const numberTag = '[object Number]';const stringTag = '[object String]';const symbolTag = '[object Symbol]';const errorTag = '[object Error]';const regexpTag = '[object RegExp]';const funcTag = '[object Function]';

const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];

function forEach(array, iteratee) {  let index = -1;  const length = array.length;  while (++index     iteratee(array[index], index);  }  return array;}

function isObject(target) {  const type = typeof target;  return target !== null && (type === 'object' || type === 'function');}

function getType(target) {  return Object.prototype.toString.call(target);}

function getInit(target) {  const Ctor = target.constructor;  return new Ctor();}

function cloneSymbol(targe) {  return Object(Symbol.prototype.valueOf.call(targe));}

function cloneReg(targe) {  const reFlags = /\w*$/;  const result = new targe.constructor(targe.source, reFlags.exec(targe));  result.lastIndex = targe.lastIndex;  return result;}

function cloneFunction(func) {  const bodyReg = /(?<={)(.|\n)+(?=})/m;  const paramReg = /(?<=\().+(?=\)\s+{)/;  const funcString = func.toString();  if (func.prototype) {    const param = paramReg.exec(funcString);    const body = bodyReg.exec(funcString);    if (body) {      if (param) {        const paramArr = param[0].split(',');        return new Function(...paramArr, body[0]);      } else {        return new Function(body[0]);      }    } else {      return null;    }  } else {    return eval(funcString);  }}

function cloneOtherType(targe, type) {  const Ctor = targe.constructor;  switch (type) {    case boolTag:    case numberTag:    case stringTag:    case errorTag:    case dateTag:      return new Ctor(targe);    case regexpTag:      return cloneReg(targe);    case symbolTag:      return cloneSymbol(targe);    case funcTag:      return cloneFunction(targe);    default:      return null;  }}

function clone(target, map = new WeakMap()) {

  // 克隆原始类型  if (!isObject(target)) {    return target;  }

  // 初始化  const type = getType(target);  let cloneTarget;  if (deepTag.includes(type)) {    cloneTarget = getInit(target, type);  } else {    return cloneOtherType(target, type);  }

  // 防止循环引用  if (map.get(target)) {    return map.get(target);  }  map.set(target, cloneTarget);

  // 克隆set  if (type === setTag) {    target.forEach(value => {      cloneTarget.add(clone(value, map));    });    return cloneTarget;  }

  // 克隆map  if (type === mapTag) {    target.forEach((value, key) => {      cloneTarget.set(key, clone(value, map));    });    return cloneTarget;  }

  // 克隆对象和数组  const keys = type === arrayTag ? undefined : Object.keys(target);  forEach(keys || target, (value, key) => {    if (keys) {      key = value;    }    cloneTarget[key] = clone(target[key], map);  });

  return cloneTarget;}

console.log(clone({  name: '张三', age: 23,  obj: { name: '李四', age: 46 },  arr: [1, 2, 3]})) // { name: '张三', age: 23, obj: { name: '李四', age: 46 }, arr: [ 1, 2, 3 ] }复制代码

对象深度克隆实际上就是要兼容Array,RegExp,Date,Function类型;
克隆函数可以用正则取出函数体和参数,再定义一个函数将取出来的值赋值进去
详细请戳对象深度拷贝

24.对象是否相等

如果用JSON.stringify转化属性顺序不同,也不相等;
而且不支持无法对函数 、RegExp等特殊对象的克隆

function deepCompare(x, y) {  var i, l, leftChain, rightChain;

  function compare2Objects(x, y) {    var p;

    // remember that NaN === NaN returns false    // and isNaN(undefined) returns true    if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {      return true;    }

    // Compare primitives and functions.         // Check if both arguments link to the same object.    // Especially useful on the step where we compare prototypes    if (x === y) {      return true;    }

    // Works in case when functions are created in constructor.    // Comparing dates is a common scenario. Another built-ins?    // We can even handle functions passed across iframes    if ((typeof x === 'function' && typeof y === 'function') ||      (x instanceof Date && y instanceof Date) ||      (x instanceof RegExp && y instanceof RegExp) ||      (x instanceof String && y instanceof String) ||      (x instanceof Number && y instanceof Number)) {      return x.toString() === y.toString();    }

    // At last checking prototypes as good as we can    if (!(x instanceof Object && y instanceof Object)) {      return false;    }

    if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {      return false;    }

    if (x.constructor !== y.constructor) {      return false;    }

    if (x.prototype !== y.prototype) {      return false;    }

    // Check for infinitive linking loops    if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {      return false;    }

    // Quick checking of one object being a subset of another.    // todo: cache the structure of arguments[0] for performance    for (p in y) {      if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {        return false;      } else if (typeof y[p] !== typeof x[p]) {        return false;      }    }

    for (p in x) {      if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {        return false;      } else if (typeof y[p] !== typeof x[p]) {        return false;      }

      switch (typeof (x[p])) {        case 'object':        case 'function':

          leftChain.push(x);          rightChain.push(y);

          if (!compare2Objects(x[p], y[p])) {            return false;          }

          leftChain.pop();          rightChain.pop();          break;

        default:          if (x[p] !== y[p]) {            return false;          }          break;      }    }

    return true;  }

  if (arguments.length     return true;   }

  for (i = 1, l = arguments.length; i     leftChain = []; //Todo: this can be cached    rightChain = [];

    if (!compare2Objects(arguments[0], arguments[i])) {      return false;    }  }

  return true;}

const obj1 = {   name: '张三', age: 23,   obj: { name: '李四', age: 46 },   arr: [1, 2, 3],  date:new Date(23),  reg: new RegExp('abc'),  fun: ()=>{} }const obj2 = {   name: '张三', age: 23,   obj: { name: '李四', age: 46 },   arr: [1, 2, 3],  date: new Date(23),  reg: new RegExp('abc'),  fun: ()=>{} }

console.log(deepCompare(obj1,obj2)) // true

复制代码

判断对象是否相等,实际上就是要处理Array,Date,RegExp,Object,Function的特殊类型是否相等

25.对象转化为字符串

通过字符串+Object 的方式来转化对象为字符串(实际上是调用 .toString() 方法)

'the Math object:' + Math.ceil(3.4)                // "the Math object:4"'the JSON object:' + {name:'曹操'}              // "the JSON object:[object Object]"复制代码

覆盖对象的toString和valueOf方法来自定义对象的类型转换

2  * { valueOf: ()=>'4' }                // 8'J' + { toString: ()=>'ava' }                // "Java"复制代码

当+用在连接字符串时,当一个对象既有toString方法又有valueOf方法时候,JS通过盲目使用valueOf方法来解决这种含糊;
对象通过valueOf方法强制转换为数字,通过toString方法强制转换为字符串

'' + {toString:()=>'S',valueOf:()=>'J'}  //J复制代码

Function

26.函数隐式返回值

(()=>3)()  //3(()=>(   3))()复制代码

函数省略大括号,或者将大括号改成小括号可以确保代码以单个语句的形式进行求值

27.函数自执行

const Func = function() {}(); // 常用

(function() {})(); // 常用(function() {}()); // 常用[function() {}()];

new function() {};new function() {}();void function() {}();typeof function() {}();delete function() {}();

+ function() {}();- function() {}();~ function() {}();! function() {}();复制代码

28.函数异步执行

Promise

Promise.reject('这是第二个 reject 值').then((data)=>{  console.log(data)}).catch(data=>{  console.log(data) //这是第二个 reject 值})复制代码

Generator

function* gen(x) {  const y = yield x + 6;  return y;}

// yield 如果用在另外一个表达式中,要放在()里面// 像上面如果是在=右边就不用加()function* genOne(x) {  const y = `这是第一个 yield 执行:${yield x + 1}`;  return y;}

const g = gen(1);//执行 Generator 会返回一个Object,而不是像普通函数返回return 后面的值g.next() // { value: 7, done: false }//调用指针的 next 方法,会从函数的头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式或return语句暂停,也就是执行yield 这一行// 执行完成会返回一个 Object,// value 就是执行 yield 后面的值,done 表示函数是否执行完毕g.next() // { value: undefined, done: true }// 因为最后一行 return y 被执行完成,所以done 为 true复制代码

Async/Await

function getSomething() {    return "something";}async function testAsync() {    return Promise.resolve("hello async");}async function test() {    const v1 = await getSomething();    const v2 = await testAsync();    console.log(v1, v2); //something 和 hello async}test();复制代码

String

29.字符串翻转

function reverseStr(str = "") {  return str.split("").reduceRight((t, v) => t + v);}

const str = "reduce123";console.log(reverseStr(str)); // "321recuder"复制代码

30.url参数序列化

将对象序列化成url参数传递

function stringifyUrl(search = {}) {  return Object.entries(search).reduce(    (t, v) => `${t}${v[0]}=${encodeURIComponent(v[1])}&`,    Object.keys(search).length ? "?" : ""  ).replace(/&$/, "");}

console.log(stringifyUrl({ age: 27, name: "YZW" })); // "?age=27&name=YZW"复制代码

31.url参数反序列化

一般会通过location.search拿到路由传递的参数,并进行反序列化得到对象

function parseUrlSearch() {  const search = '?age=25&name=TYJ'  return search.replace(/(^\?)|(&$)/g, "").split("&").reduce((t, v) => {    const [key, val] = v.split("=");    t[key] = decodeURIComponent(val);    return t;  }, {});}

console.log(parseUrlSearch()); // { age: "25", name: "TYJ" }复制代码

32.转化为字符串

const val = 1 + ""; // 通过+ ''空字符串转化console.log(val); // "1"console.log(typeof val); // "string"

const val1 = String(1);console.log(val1); // "1"console.log(typeof val1); // "string"复制代码

Number

33.数字千分位

方法一:

function thousandNum(num = 0) {  const str = (+num).toString().split(".");  const int = nums => nums.split("").reverse().reduceRight((t, v, i) => t + (i % 3 ? v : `${v},`), "").replace(/^,|,$/g, "");  const dec = nums => nums.split("").reduce((t, v, i) => t + ((i + 1) % 3 ? v : `${v},`), "").replace(/^,|,$/g, "");  return str.length > 1 ? `${int(str[0])}.${dec(str[1])}` : int(str[0]);}

thousandNum(1234); // "1,234"thousandNum(1234.00); // "1,234"thousandNum(0.1234); // "0.123,4"console.log(thousandNum(1234.5678)); // "1,234.567,8"复制代码

方法二

console.log('1234567890'.replace(/\B(?=(\d{3})+(?!\d))/g, ","))console.log((1234567890).toLocaleString())复制代码

34.字符串转数字

方法一
用*1来转化为数字,实际上是调用.valueOf方法

'32' * 1            // 32'ds' * 1            // NaNnull * 1            // 0undefined * 1    // NaN1  * { valueOf: ()=>'3' }        // 3复制代码

方法二

+ '123'            // 123+ 'ds'               // NaN+ ''                    // 0+ null              // 0+ undefined    // NaN+ { valueOf: ()=>'3' }    // 3复制代码

35.判断小数是否相等

肯定有人会说这还不简单,直接用'==='比较;
实际上0.1+0.2 !==0.3,因为计算机不能精确表示0.1, 0.2这样的浮点数,所以相加就不是0.3了

Number.EPSILON=(function(){   //解决兼容性问题    return Number.EPSILON?Number.EPSILON:Math.pow(2,-52);})();//上面是一个自调用函数,当JS文件刚加载到内存中,就会去判断并返回一个结果function numbersequal(a,b){     return Math.abs(a-b)  }//接下来再判断   const a=0.1+0.2, b=0.3;console.log(numbersequal(a,b)); //这里就为true了复制代码

36.双位运算符

双位运算符比Math.floor(),Math.ceil()速度快

~~7.5                // 7Math.ceil(7.5)       // 8Math.floor(7.5)      // 7

~~-7.5          // -7Math.floor(-7.5)     // -8Math.ceil(-7.5)      // -7复制代码

所以负数时,双位运算符和Math.ceil结果一致,正数时和Math.floor结果一致

37.取整和奇偶性判断

取整

3.3 | 0         // 3-3.9 | 0        // -3

parseInt(3.3)  // 3parseInt(-3.3) // -3

// 四舍五入取整Math.round(3.3) // 3Math.round(-3.3) // -3

// 向上取整Math.ceil(3.3) // 4Math.ceil(-3.3) // -3

// 向下取整Math.floor(3.3) // 3Math.floor(-3.3) // -4复制代码

判断奇偶数

const num=5;!!(num & 1) // true!!(num % 2) // true复制代码

Boolean

38.判断数据类型

function dataTypeJudge(val, type) {  const dataType = Object.prototype.toString.call(val).replace(/\[object (\w+)\]/, "$1").toLowerCase();  return type ? dataType === type : dataType;}console.log(dataTypeJudge("young")); // "string"console.log(dataTypeJudge(20190214)); // "number"console.log(dataTypeJudge(true)); // "boolean"console.log(dataTypeJudge([], "array")); // trueconsole.log(dataTypeJudge({}, "array")); // false复制代码

可判断类型:undefined、null、string、number、boolean、array、object、symbol、date、regexp、function、asyncfunction、arguments、set、map、weakset、weakmap

39.使用Boolean过滤数组假值

const compact = arr => arr.filter(Boolean)compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34])  //[ 1, 2, 3, 'a', 's', 34 ]复制代码

40.短路运算

||(或)

const flag = false || true //true// 某个值为假时可以给默认值const arr = false || []复制代码

&&(与)

const flag1 = false && true //falseconst flag2 = true && true //true复制代码

41.switch 简写

可以用对象替代switch,提高代码可读性

switch(a) {  case '张三':    return 'age是12'  case '李四':    return 'age是120'}

// 使用对象替换后const obj ={  '张三': 'age12',  '李四': 'age120',}console.log(obj['张三'])复制代码

结语

源码地址 https://github.com/lanzhsh/react-vue-koa/tree/master/js/skill;
原创码字不易,欢迎start!

- END -近期你可以这样优化 if-else 代码结构

重新认识Typescript | Vue3源码系列

在看的都是铁汁❤️

js数组按中文拼音排序_收藏 | JS开发必须知道的41个技巧相关推荐

  1. js数组按中文拼音排序_通俗易懂讲 Python 算法:快速排序

    原文:https://stackabuse.com/quicksort-in-python/ 作者:Marcus Sanatan 译者:老齐 欢迎在 bilibili  搜索 freeCodeCamp ...

  2. js数组按中文拼音排序_学习排序算法,结合这个方法太容易理解了

    排序是一个经典的问题,它以一定的顺序对一个数组或列表中的元素进行重新排序.而排序算法也是各有千秋,每个都有自身的优点和局限性.虽然这些算法平常根本就不用自己去编写,但作为一个有追求的程序员,还是要了解 ...

  3. 收藏 | JS开发必须知道的41个技巧

    [本文来自转载]Vue中文社区 转载来自-作者:火狼-腾讯云开发文章: 腾讯云开发文章 本博客转载源码地址: https://github.com/lanzhsh/react-vue-koa 2, O ...

  4. js数组按中文拼音排序_JavaScript数组

    1.什么是数组 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素,数组是一种将一组数据存储在单个变量名下的优雅方式 2.创建方式 在js中数组的创建方式有2种 a.利用 ...

  5. php 按汉字拼音排序,php 数组按中文拼音排序

    本篇文章给大家分享的内容是关于php数组按中文拼音排序,有着一定的参考价值,有需要的朋友可以参考一下 $str = "我们可以在浏览器中看到,当鼠标移到元素上时,元素开始向右移动,开始比较慢 ...

  6. mysql按中文拼音排序_按拼音排序,mysql 按中文拼音顺序排序

    1,简单方法 如果字符集采用的是 gbk(汉字编码字符集),直接在查询语句后边添加 ORDER BY: SELECT * FROM table ORDER BY title; 如果字符集采用的是 ut ...

  7. python怎么学比较有技巧_学python必须知道的30个技巧

    收集这些有用的捷径技巧 1. 原地进行交换两个数字 我们对赋值的右侧进行一个新的元组,左侧解析(unpack)那个(未被引用的)元组到变量 和 赋值完成时,新的元组变成了未被引用状态并且被标记没用处, ...

  8. 乌班图好玩的命令_乌班图必须知道的60个命令

    Linux 提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作.文件存取.目 录操作.进程管理.文件权限设定等.所以,在 Linux 系统上工作离不开使用系统提供的命 令.要想真正理解 Li ...

  9. rsa 模数 指数转换 c语言_模数转换,你必须知道的8个经典ADC转换电路方案

    模数转换器即A/D转换器,或简称ADC,通常是指一个将模拟信号转变为数字信号的电子元件.通常的模数转换器是将一个输入电压信号转换为一个输出的数字信号.由于数字信号本身不具有实际意义,仅仅表示一个相对大 ...

最新文章

  1. maven的setting.xml文件配置信息【仅仅更改了一处】
  2. 潜在狄利克雷分配(LDA,Latent Dirichlet Allocation)模型(三)
  3. 遇到困难挫折也不要悲观:每个人生来就是冠军(转)
  4. 文件管理系统_我的文件管理系统
  5. 在MSN、QQ群、论坛上提问的决窍
  6. 【JavaSE01】初识Java-思维导图
  7. 网易云信三周年:我们只做第一
  8. VTK:几何对象之Arrow
  9. 初始化HashMap的默认值——阿里巴巴编码规范系列
  10. 使用thinkPHP做注册程序的实例
  11. UE4 调整引擎功能的级别
  12. docker存储--理解镜像文件系统aufs/device mapper、主机存储共享、容器间存储共享、分布式存储Flocker
  13. 报表中表达式的全局集合(Visual Studio 报表设计器)
  14. PyTorch 中如何指定GPU
  15. flutter能开发游戏吗_Flutter开发游戏初体验,喜大普奔
  16. VCPKG 常用命令
  17. 特殊字符图案大全c语言,特殊符号大全
  18. Java常用工具类-根据物流单号,从快递100中获取物流详细信息,包含发货,签收等
  19. 计算机技能比赛培训总结怎么写,技能大赛总结范文
  20. 【杂七杂八】《我叫MT online》反编译解析

热门文章

  1. EasyFlash源码分析记录
  2. 华为手机卡顿怎么解决
  3. vi/vim 总结 | emacs evil 使用教程
  4. 金佩姗 - 决 歌词
  5. VMware 新建虚拟机
  6. python进阶之学习笔记_干货 | Python进阶系列之学习笔记(二)
  7. 使用TensorFlow玩GTA5
  8. JUC进阶之路-Java的内存模型JMM
  9. JavaScript 数据类型详解(对象、set、map)
  10. linux查看server端口占用,Linux查看端口占用的命令