41个最新的JavaScript开发技巧,你必须要知道

发表于 4年以前  | 总阅读数:634 次

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

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

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(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]) //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 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)  // 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['张三'])

本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/QetU7iwwdeZKudhHdWIjjQ

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Java 中验证时间格式的 4 种方法 2年以前  |  3870次阅读
Java经典面试题答案解析(1-80题) 4年以前  |  3651次阅读
CentOS 配置java应用开机自动启动 4年以前  |  2797次阅读
IDEA依赖冲突分析神器—Maven Helper 4年以前  |  2772次阅读
SpringBoot 控制并发登录的人数教程 4年以前  |  2452次阅读
 目录