js开发常用的40个技巧

js-tricks.jpg

前言

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!

以上是 js开发常用的40个技巧 的全部内容, 来源链接: utcz.com/a/33950.html

回到顶部