分享:41个最新的JavaScript开发技巧 !

前 言

JS是前端的核心,但有些使用技巧你还不一定知道。本文梳理了JS的41个技巧,帮助大家提高JS的使用技巧。

 

Array

数组交集

普通数组

  •  
  •  
  •  
  •  
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数据类型

  •  
  •  
  •  
  •  
  •  
  •  
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 }]

 

数组并集

普通数组

  •  
  •  
  •  
  •  
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]

 

数组对象

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
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 }]

 

数组差集

数组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 } ]

 

数组补集

两个数组各自没有的集合

普通数组

  •  
  •  
  •  
  •  
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所没有的集合,补集是两个数组各自没有的集合

数组去重

普通数组

  •  
  •  
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 obj = [];const result = arr.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 }]

 

数组排序

普通数组

  •  
  •  
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 是降序。

最大值

普通数组

  •  
  •  
  •  
  •  
  •  
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

 

数组求和

普通数组

  •  
  •  
  •  
[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)

 

数组合并

普通数组

  •  
  •  
  •  
  •  
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 =Array.prototype.push.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 } ]

 

数组是否包含值

普通数组

  •  
  •  
  •  
  •  
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)

 

数组每一项都满足

普通数组

  •  
[1, 2, 3].every(item => { return item > 2 })

 

数组对象

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

 

数组有一项满足

普通数组

  •  
[1, 2, 3].some(item => { return item > 2 })

 

数组对象

  •  
  •  
const arr = [{ age: 3 }, { age: 4 }, { age: 5 }]arr.some(item => { return item.age < 4 }) // true

 

版本号排序

方法一

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
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 < c.length; 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的后面

对象转数组

将数组的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}

 

数组转对象

将数组的值转化为对象的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" }]

 

数组解构

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

 

 

Object

对象变量属性

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

 

对象多余属性删除

  •  
  •  
  •  
  •  
const { name, age, ...obj } = { name: "张三", age: 13, dec: "描述1", info: "信息" }console.log(name)  // 张三console.log(age)  // 13console.log(obj)  // {dec: "描述1", info: "信息" }

 

对象嵌套属性解构

  •  
  •  
const { info:{ dec} } = { name: "张三", age: 13, info:{dec: "描述1", info: "信息" }}console.log(dec) // 描述1

 

解构对象属性别名

  •  
  •  
const { name:newName } = { name: "张三", age: 13 }console.log(newName)  // 张三

 

解构对象属性默认值

  •  
  •  
const { dec="这是默认dec值" } = { name: "张三", age: 13 }console.log(dec) //这是默认dec值

 

拦截对象

利用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); // 这是改变值1let 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 24return Reflect.set(target, key, value, receiver);  }};let proxy = new Proxy(obj, handler);proxy.name = "李四";proxy.age = 24;

 

defineProterty和proxy的对比:

defineProterty是es5的标准,proxy是es6的标准;

proxy可以监听到数组索引赋值,改变数组长度的变化;

proxy是监听对象,不用深层遍历,defineProterty是监听属性;

利用defineProterty实现双向数据绑定(vue2.x采用的核心)

对象深度拷贝

JSON.stringify深度克隆对象

无法对函数 、RegExp等特殊对象的克隆;

会抛弃对象的constructor,所有的构造函数会指向Object;

对象有循环引用,会报错。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
const objDeepClone = obj => {return clone(obj)}const isType = (obj, type) => {if (typeof obj !== "object") return false;// 判断数据类型的经典方法:const typeString = Object.prototype.toString.call(obj);  let flag;switch (type) {case "Array":      flag = typeString === "[object Array]";break;case "Date":      flag = typeString === "[object Date]";break;case "RegExp":      flag = typeString === "[object RegExp]";break;default:      flag = false;  }return flag;};/*** deep clone* @param  {[type]} parent object 需要进行克隆的对象* @return {[type]}        深克隆后的对象*/const clone = parent => {// 维护两个储存循环引用的数组const parents = []const children = []const _clone = parent => {if (parent === null) return nullif (typeof parent !== "object") return parent    let child, protoif (isType(parent, "Array")) {// 对数组做特殊处理      child = []    } else if (isType(parent, "RegExp")) {// 对正则对象做特殊处理      child = new RegExp(parent.source, getRegExp(parent))if (parent.lastIndex) child.lastIndex = parent.lastIndex    } else if (isType(parent, "Date")) {// 对Date对象做特殊处理      child = new Date(parent.getTime())    } else {// 处理对象原型      proto = Object.getPrototypeOf(parent)// 利用Object.create切断原型链      child = Object.create(proto)    }// 处理循环引用const index = parents.indexOf(parent)if (index !== -1) {// 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象return children[index]    }    parents.push(parent)    children.push(child)for (const i in parent) {// 递归      child[i] = _clone(parent[i])    }return child  }return _clone(parent)}console.log(objDeepClone({   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类型;

克隆函数可以用正则取出函数体和参数,再定义一个函数将取出来的值赋值进去详细请戳对象深度拷贝

对象是否相等

如果用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 trueif (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 prototypesif (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 iframesif ((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 canif (!(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 loopsif (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 performancefor (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 < 1) {return true;   }for (i = 1, l = arguments.length; i < l; 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的特殊类型是否相等

对象转化为字符串

通过字符串+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

函数隐式返回值

  •  
  •  
  •  
  •  
(()=>3)()  //3(()=>(3))()

 

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

函数自执行

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
const Func = function() {}(); // 常用(function() {})(); // 常用(function() {}()); // 常用[function() {}()];new function() {};new function() {}();void function() {}();typeof function() {}();delete function() {}();+ function() {}();- function() {}();~ function() {}();! function() {}();

 

函数异步执行

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

字符串翻转

  •  
  •  
  •  
  •  
  •  
  •  
function reverseStr(str = "") {return str.split("").reduceRight((t, v) => t + v);}const str = "reduce123";console.log(reverseStr(str)); // "123recuder"

 

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"

 

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" }

 

转化为字符串

  •  
  •  
  •  
  •  
  •  
  •  
  •  
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

数字千分位

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
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"

 

字符串转数字

方法一

用*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

 

判断小数是否相等

肯定有人会说这还不简单,直接用"==="比较;实际上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)<Number.EPSILON;  }//接下来再判断   const a=0.1+0.2, b=0.3;console.log(numbersequal(a,b)); //这里就为true了

 

双位运算符

双位运算符比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结果一致

取整和奇偶性判断

取整

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
3.3 | 0         // 3-3.9 | 0        // -3parseInt(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

判断数据类型

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
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

使用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 ]

 

短路运算

||(或)

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

 

&&(与)

  •  
  •  
const flag1 = false && true //falseconst flag2 = true && true //true

 

switch 简写

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

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
switch(a) {case "张三":return "age是12"case "李四":return "age是120"}// 使用对象替换后const obj ={"张三": "age12","李四": "age120",}console.log(obj["张三"])

 

The end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值