乐趣区

关于javascript:JS开发必须知道的41个技巧持续更新

前言

JS 是前端的外围,但有些应用技巧你还不肯定晓得;
本文梳理了 JS 的 41 个技巧,帮忙大家进步 JS 的应用技巧;
文章有点长,能够 clone 下源码,间接撸,源码地址请戳全副源码,原创不易,欢送 star;
序列文章:
Vue 开发必须晓得的 36 个技巧
React 开发必须晓得的 34 个技巧

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

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 => !arr2.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}]

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

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(arr1) // [{name: 'Bob', age: 22}, {name: 'Rom', age: 12}]
console.log(arr2) // [{ 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]) //4
Math.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].id
console.log(arr1) // 4
console.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) //3
console.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 =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} ]

10. 数组是否蕴含值

一般数组

console.log([1, 2, 3].includes(4)) //false
console.log([1, 2, 3].indexOf(4)) //-1 如果存在换回索引
console.log([1, 2, 3].find((item) => item === 3)) //3 如果数组中无值返回 undefined
console.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 < 4}) // 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 < 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 的前面

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 param1 = 1;
const param2 = 2;
[param1, param2] = [param2, param1]; // 相当于替换了数组地位
console.log(param1) // 2
console.log(param2) // 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)  // 13
console.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); // 这是扭转值 1
console.log(obj.age);  // 这是扭转值 1
console.log(obj.sex); // 这是扭转值 1

let objOne = {}, defaultNameOne = "这是默认值 2";
Object.defineProperty(obj, 'name', {get() {return defaultNameOne;},
  set(value) {defaultNameOne = value;}
});
console.log(objOne.name); // undefined
objOne.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 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 null
    if (typeof parent !== 'object') return parent

    let child, proto

    if (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 类型;
克隆函数能够用正则取出函数体和参数,再定义一个函数将取出来的值赋值进去
具体请戳对象深度拷贝

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 < 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 的非凡类型是否相等

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)); // "123recuder"

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"

34. 字符串转数字

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

'32' * 1            // 32
'ds' * 1            // NaN
null * 1            // 0
undefined * 1    // NaN
1  * {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)<Number.EPSILON;
  }
// 接下来再判断   
const a=0.1+0.2, b=0.3;
console.log(numbersequal(a,b)); // 这里就为 true 了

36. 双位运算符

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

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


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

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

37. 取整和奇偶性判断

取整

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

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

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

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

// 向下取整
Math.floor(3.3) // 3
Math.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")); // true
console.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 //false
const flag2 = true || true //true

41.switch 简写

能够用对象代替 switch,进步代码可读性

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

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

结语

源码地址请戳全副源码;
原创码字不易,欢送 start!

退出移动版