热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Github上73个超棒且可提高生产力的NPM包,高赞!

来自:掘金,作者:火狼1https:juejin.impost6854573212890562573前言JS是前端的核心,但

来自:掘金,作者:火狼1

https://juejin.im/post/6854573212890562573

前言

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

目录

  • Array

    • 1.数组交集

    • 2.数组并集

    • 3.数组差集

    • 4.数组补集

    • 5.数组去重

    • 6.数组排序

    • 7.最大值

    • 8.数组求和

    • 9.数组合并

    • 10.数组是否包含值

    • 11.数组每一项都满足

    • 12.数组有一项满足

    • 13.版本号排序

    • 14. 对象转数组

    • 15.数组转对象

    • 16.数组解构

  • Object

    • 17.对象变量属性

    • 18.对象多余属性删除

    • 19.对象嵌套属性解构

    • 20.解构对象属性别名

    • 21.解构对象属性默认值

    • 22.拦截对象

    • 23.对象深度拷贝

    • 24.对象是否相等

    • 25.对象转化为字符串

  • Function

    • 26.函数隐式返回值

    • 27.函数自执行

    • 28.函数异步执行

  • String

    • 29.字符串翻转

    • 30.url参数序列化

    • 31.url参数反序列化

    • 32.转化为字符串

  • Number

    • 33.数字千分位

    • 34.字符串转数字

    • 35.判断小数是否相等

    • 36.双位运算符

    • 37.取整和奇偶性判断

  • Boolean

    • 38.判断数据类型

    • 39.使用Boolean过滤数组假值

    • 40.短路运算

    • 41.switch 简写

Array

1.数组交集

普通数组

const arr1 = [1, 2, 3, 4, 5 , 8 ,9],arr2 = [5, 6, 7, 8, 9];const interp = arr1.filter(function (val) { return arr2.indexOf(val) > -1 })
console.log(interp) //[5, 8, 9]

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

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

2.数组并集

普通数组

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

数组对象

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

3.数组差集

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

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

数组对象

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

4.数组补集

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

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

数组对象

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

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

5.数组去重

普通数组

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

数组对象

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

6.数组排序

普通数组

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

数组对象

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

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

7.最大值

普通数组

Math.max(...[1, 2, 3, 4]) //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 =[].concat.apply(arrA, arrB)//arrA值为[1,2,3,4]

数组对象

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

10.数组是否包含值

普通数组

console.log([1, 2, 3].includes(4)) //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 &#61;> { return item.age < 4 }) // true

13.版本号排序

方法一

function sortNumber(a, b) {return a - b
}
const b &#61; [1,2,3,7,5,6]
const a &#61; ["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)); //[ &#39;1.1000&#39;, &#39;1.1&#39;, &#39;1.25&#39;, &#39;1.40&#39;, &#39;1.5&#39;, &#39;1.5&#39; ]

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

方法二

//假定字符串的每节数都在5位以下
//去除数组空值||空格
if (!Array.prototype.trim) {Array.prototype.trim &#61; function () {let arr &#61; []; this.forEach(function (e) {if (e.match(/\S&#43;/)) arr.push(e);})return arr;}
}//提取数字部分
function toNum(a) {let d &#61; a.toString();let c &#61; d.split(/\D/).trim();let num_place &#61; ["", "0", "00", "000", "0000"], r &#61; num_place.reverse();for (let i &#61; 0; i < c.length; i&#43;&#43;) {let len &#61; c[i].length;c[i] &#61; r[len] &#43; c[i];}let res &#61; c.join(&#39;&#39;);return res;
}//提取字符
function toChar(a) {let d &#61; a.toString();let c &#61; d.split(/\.|\d/).join(&#39;&#39;);return c;
}function sortVersions(a, b) {let _a1 &#61; toNum(a), _b1 &#61; toNum(b);if (_a1 !&#61;&#61; _b1) return _a1 - _b1;else {_a2 &#61; toChar(a).charCodeAt(0).toString(16);_b2 &#61; toChar(b).charCodeAt(0).toString(16);return _a2 - _b2;}
}let arr1 &#61; ["10", "5", "40", "25", "1000", "1"];
let arr2 &#61; ["1.10", "1.5", "1.40", "1.25", "1.1000", "1.1"];
let arr3 &#61; ["1.10c", "1.10b", "1.10C", "1.25", "1.1000", "1.10A"];
console.log(arr1.sort(sortVersions)) //[ &#39;1&#39;, &#39;5&#39;, &#39;10&#39;, &#39;25&#39;, &#39;40&#39;, &#39;1000&#39; ]
console.log(arr2.sort(sortVersions)) //[ &#39;1.1&#39;, &#39;1.5&#39;, &#39;1.10&#39;, &#39;1.25&#39;, &#39;1.40&#39;, &#39;1.1000&#39; ]
console.log(arr3.sort(sortVersions)) // [ &#39;1.10A&#39;, &#39;1.10C&#39;, &#39;1.10b&#39;, &#39;1.10c&#39;, &#39;1.25&#39;, &#39;1.1000&#39; ]

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

14. 对象转数组

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

Object.keys({ name: &#39;张三&#39;, age: 14 }) //[&#39;name&#39;,&#39;age&#39;]
Object.values({ name: &#39;张三&#39;, age: 14 }) //[&#39;张三&#39;,14]
Object.entries({ name: &#39;张三&#39;, age: 14 }) //[[name,&#39;张三&#39;],[age,14]]
Object.fromEntries([name, &#39;张三&#39;], [age, 14]) //ES10的api,Chrome不支持 , firebox输出{name:&#39;张三&#39;,age:14}

15.数组转对象

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

const arrName &#61; [&#39;张三&#39;, &#39;李四&#39;, &#39;王五&#39;]
const arrAge&#61;[&#39;20&#39;,&#39;30&#39;,&#39;40&#39;]
const arrDec &#61; [&#39;描述1&#39;, &#39;描述2&#39;, &#39;描述3&#39;]
const obj &#61; arrName.map((item,index)&#61;>{return { name: item, age: arrAge[index],dec:arrDec[index]}
})console.log(obj) // [{ name: &#39;张三&#39;, age: &#39;20&#39;, dec: &#39;描述1&#39; },{ name: &#39;李四&#39;, age: &#39;30&#39;, dec: &#39;描述2&#39; },{ name: &#39;王五&#39;, age: &#39;40&#39;, dec: &#39;描述3&#39; }]

16.数组解构

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

Object

17.对象变量属性

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

18.对象多余属性删除

const { name, age, ...obj } &#61; { name: &#39;张三&#39;, age: 13, dec: &#39;描述1&#39;, info: &#39;信息&#39; }
console.log(name)  // 张三
console.log(age)  // 13
console.log(obj)  // {dec: &#39;描述1&#39;, info: &#39;信息&#39; }

19.对象嵌套属性解构

const { info:{ dec} } &#61; { name: &#39;张三&#39;, age: 13, info:{dec: &#39;描述1&#39;, info: &#39;信息&#39; }}
console.log(dec) // 描述1

20.解构对象属性别名

const { name:newName } &#61; { name: &#39;张三&#39;, age: 13 }
console.log(newName)  // 张三

21.解构对象属性默认值

const { dec&#61;&#39;这是默认dec值&#39; } &#61; { name: &#39;张三&#39;, age: 13 }
console.log(dec) //这是默认dec值

22.拦截对象

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

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

利用proxy拦截对象

let obj &#61; { name: &#39;&#39;, age: &#39;&#39;, sex: &#39;&#39; }
let handler &#61; {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 &#61; new Proxy(obj, handler);
proxy.name &#61; "李四";
proxy.age &#61; 24;

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

23.对象深度拷贝

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

const mapTag &#61; &#39;[object Map]&#39;;
const setTag &#61; &#39;[object Set]&#39;;
const arrayTag &#61; &#39;[object Array]&#39;;
const objectTag &#61; &#39;[object Object]&#39;;
const argsTag &#61; &#39;[object Arguments]&#39;;const boolTag &#61; &#39;[object Boolean]&#39;;
const dateTag &#61; &#39;[object Date]&#39;;
const numberTag &#61; &#39;[object Number]&#39;;
const stringTag &#61; &#39;[object String]&#39;;
const symbolTag &#61; &#39;[object Symbol]&#39;;
const errorTag &#61; &#39;[object Error]&#39;;
const regexpTag &#61; &#39;[object RegExp]&#39;;
const funcTag &#61; &#39;[object Function]&#39;;const deepTag &#61; [mapTag, setTag, arrayTag, objectTag, argsTag];function forEach(array, iteratee) {let index &#61; -1;const length &#61; array.length;while (&#43;&#43;index < length) {iteratee(array[index], index);}return array;
}function isObject(target) {const type &#61; typeof target;return target !&#61;&#61; null && (type &#61;&#61;&#61; &#39;object&#39; || type &#61;&#61;&#61; &#39;function&#39;);
}function getType(target) {return Object.prototype.toString.call(target);
}function getInit(target) {const Ctor &#61; target.constructor;return new Ctor();
}function cloneSymbol(targe) {return Object(Symbol.prototype.valueOf.call(targe));
}function cloneReg(targe) {const reFlags &#61; /\w*$/;const result &#61; new targe.constructor(targe.source, reFlags.exec(targe));result.lastIndex &#61; targe.lastIndex;return result;
}function cloneFunction(func) {const bodyReg &#61; /(?<&#61;{)(.|\n)&#43;(?&#61;})/m;const paramReg &#61; /(?<&#61;\().&#43;(?&#61;\)\s&#43;{)/;const funcString &#61; func.toString();if (func.prototype) {const param &#61; paramReg.exec(funcString);const body &#61; bodyReg.exec(funcString);if (body) {if (param) {const paramArr &#61; param[0].split(&#39;,&#39;);return new Function(...paramArr, body[0]);} else {return new Function(body[0]);}} else {return null;}} else {return eval(funcString);}
}function cloneOtherType(targe, type) {const Ctor &#61; targe.constructor;switch (type) {case boolTag:case numberTag:case stringTag:case errorTag:case dateTag:return new Ctor(targe);case regexpTag:return cloneReg(targe);case symbolTag:return cloneSymbol(targe);case funcTag:return cloneFunction(targe);default:return null;}
}function clone(target, map &#61; new WeakMap()) {// 克隆原始类型if (!isObject(target)) {return target;}// 初始化const type &#61; getType(target);let cloneTarget;if (deepTag.includes(type)) {cloneTarget &#61; getInit(target, type);} else {return cloneOtherType(target, type);}// 防止循环引用if (map.get(target)) {return map.get(target);}map.set(target, cloneTarget);// 克隆setif (type &#61;&#61;&#61; setTag) {target.forEach(value &#61;> {cloneTarget.add(clone(value, map));});return cloneTarget;}// 克隆mapif (type &#61;&#61;&#61; mapTag) {target.forEach((value, key) &#61;> {cloneTarget.set(key, clone(value, map));});return cloneTarget;}// 克隆对象和数组const keys &#61; type &#61;&#61;&#61; arrayTag ? undefined : Object.keys(target);forEach(keys || target, (value, key) &#61;> {if (keys) {key &#61; value;}cloneTarget[key] &#61; clone(target[key], map);});return cloneTarget;
}console.log(clone({name: &#39;张三&#39;, age: 23,obj: { name: &#39;李四&#39;, age: 46 },arr: [1, 2, 3]
})) // { name: &#39;张三&#39;, age: 23, obj: { name: &#39;李四&#39;, age: 46 }, arr: [ 1, 2, 3 ] }

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

24.对象是否相等

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


function deepCompare(x, y) {var i, l, leftChain, rightChain;function compare2Objects(x, y) {var p;// remember that NaN &#61;&#61;&#61; NaN returns false// and isNaN(undefined) returns trueif (isNaN(x) && isNaN(y) && typeof x &#61;&#61;&#61; &#39;number&#39; && typeof y &#61;&#61;&#61; &#39;number&#39;) {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 &#61;&#61;&#61; 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 &#61;&#61;&#61; &#39;function&#39; && typeof y &#61;&#61;&#61; &#39;function&#39;) ||(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() &#61;&#61;&#61; 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 !&#61;&#61; y.constructor) {return false;}if (x.prototype !&#61;&#61; 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) !&#61;&#61; x.hasOwnProperty(p)) {return false;} else if (typeof y[p] !&#61;&#61; typeof x[p]) {return false;}}for (p in x) {if (y.hasOwnProperty(p) !&#61;&#61; x.hasOwnProperty(p)) {return false;} else if (typeof y[p] !&#61;&#61; typeof x[p]) {return false;}switch (typeof (x[p])) {case &#39;object&#39;:case &#39;function&#39;:leftChain.push(x);rightChain.push(y);if (!compare2Objects(x[p], y[p])) {return false;}leftChain.pop();rightChain.pop();break;default:if (x[p] !&#61;&#61; y[p]) {return false;}break;}}return true;}if (arguments.length < 1) {return true; }for (i &#61; 1, l &#61; arguments.length; i < l; i&#43;&#43;) {leftChain &#61; []; //Todo: this can be cachedrightChain &#61; [];if (!compare2Objects(arguments[0], arguments[i])) {return false;}}return true;
}const obj1 &#61; { name: &#39;张三&#39;, age: 23, obj: { name: &#39;李四&#39;, age: 46 }, arr: [1, 2, 3],date:new Date(23),reg: new RegExp(&#39;abc&#39;),fun: ()&#61;>{}}
const obj2 &#61; { name: &#39;张三&#39;, age: 23, obj: { name: &#39;李四&#39;, age: 46 }, arr: [1, 2, 3],date: new Date(23),reg: new RegExp(&#39;abc&#39;),fun: ()&#61;>{}}console.log(deepCompare(obj1,obj2)) // true

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

25.对象转化为字符串

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

&#39;the Math object:&#39; &#43; Math.ceil(3.4)                // "the Math object:4"
&#39;the JSON object:&#39; &#43; {name:&#39;曹操&#39;}              // "the JSON object:[object Object]"

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

2  * { valueOf: ()&#61;>&#39;4&#39; }                // 8
&#39;J&#39; &#43; { toString: ()&#61;>&#39;ava&#39; }                // "Java"

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

&#39;&#39; &#43; {toString:()&#61;>&#39;S&#39;,valueOf:()&#61;>&#39;J&#39;}  //J

Function

26.函数隐式返回值

(()&#61;>3)()  //3
(()&#61;>(3
))()

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

27.函数自执行

const Func &#61; function() {}(); // 常用(function() {})(); // 常用
(function() {}()); // 常用
[function() {}()];new function() {};
new function() {}();
void function() {}();
typeof function() {}();
delete function() {}();&#43; function() {}();
- function() {}();
~ function() {}();
! function() {}();

28.函数异步执行

Promise

Promise.reject(&#39;这是第二个 reject 值&#39;).then((data)&#61;>{console.log(data)
}).catch(data&#61;>{console.log(data) //这是第二个 reject 值
})

Generator

function* gen(x) {const y &#61; yield x &#43; 6;return y;
}// yield 如果用在另外一个表达式中,要放在()里面
// 像上面如果是在&#61;右边就不用加()
function* genOne(x) {const y &#61; &#96;这是第一个 yield 执行:${yield x &#43; 1}&#96;;return y;
}const g &#61; gen(1);
//执行 Generator 会返回一个Object,而不是像普通函数返回return 后面的值
g.next() // { value: 7, done: false }
//调用指针的 next 方法,会从函数的头部或上一次停下来的地方开始执行&#xff0c;直到遇到下一个 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 &#61; await getSomething();const v2 &#61; await testAsync();console.log(v1, v2); //something 和 hello async
}
test();

String

29.字符串翻转

function reverseStr(str &#61; "") {return str.split("").reduceRight((t, v) &#61;> t &#43; v);
}const str &#61; "reduce123";
console.log(reverseStr(str)); // "321recuder"

30.url参数序列化

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

function stringifyUrl(search &#61; {}) {return Object.entries(search).reduce((t, v) &#61;> &#96;${t}${v[0]}&#61;${encodeURIComponent(v[1])}&&#96;,Object.keys(search).length ? "?" : "").replace(/&$/, "");
}console.log(stringifyUrl({ age: 27, name: "YZW" })); // "?age&#61;27&name&#61;YZW"

31.url参数反序列化

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

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

32.转化为字符串

const val &#61; 1 &#43; ""; // 通过&#43; &#39;&#39;空字符串转化
console.log(val); // "1"
console.log(typeof val); // "string"const val1 &#61; String(1);
console.log(val1); // "1"
console.log(typeof val1); // "string"

Number

33.数字千分位

方法一&#xff1a;

function thousandNum(num &#61; 0) {const str &#61; (&#43;num).toString().split(".");const int &#61; nums &#61;> nums.split("").reverse().reduceRight((t, v, i) &#61;> t &#43; (i % 3 ? v : &#96;${v},&#96;), "").replace(/^,|,$/g, "");const dec &#61; nums &#61;> nums.split("").reduce((t, v, i) &#61;> t &#43; ((i &#43; 1) % 3 ? v : &#96;${v},&#96;), "").replace(/^,|,$/g, "");return str.length > 1 ? &#96;${int(str[0])}.${dec(str[1])}&#96; : int(str[0]);
}thousandNum(1234); // "1,234"
thousandNum(1234.00); // "1,234"
thousandNum(0.1234); // "0.123,4"
console.log(thousandNum(1234.5678)); // "1,234.567,8"

方法二

console.log(&#39;1234567890&#39;.replace(/\B(?&#61;(\d{3})&#43;(?!\d))/g, ","))
console.log((1234567890).toLocaleString())

34.字符串转数字

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

&#39;32&#39; * 1            // 32
&#39;ds&#39; * 1            // NaN
null * 1            // 0
undefined * 1    // NaN
1  * { valueOf: ()&#61;>&#39;3&#39; }        // 3

方法二

&#43; &#39;123&#39;            // 123
&#43; &#39;ds&#39;               // NaN
&#43; &#39;&#39;                    // 0
&#43; null              // 0
&#43; undefined    // NaN
&#43; { valueOf: ()&#61;>&#39;3&#39; }    // 3

35.判断小数是否相等

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

Number.EPSILON&#61;(function(){   //解决兼容性问题return Number.EPSILON?Number.EPSILON:Math.pow(2,-52);
})();
//上面是一个自调用函数&#xff0c;当JS文件刚加载到内存中&#xff0c;就会去判断并返回一个结果
function numbersequal(a,b){ return Math.abs(a-b)//接下来再判断   
const a&#61;0.1&#43;0.2, b&#61;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

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

37.取整和奇偶性判断

取整

3.3 | 0         // 3
-3.9 | 0        // -3parseInt(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&#61;5;
!!(num & 1) // true
!!(num % 2) // true

Boolean

38.判断数据类型

function dataTypeJudge(val, type) {const dataType &#61; Object.prototype.toString.call(val).replace(/\[object (\w&#43;)\]/, "$1").toLowerCase();return type ? dataType &#61;&#61;&#61; 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

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

39.使用Boolean过滤数组假值

const compact &#61; arr &#61;> arr.filter(Boolean)
compact([0, 1, false, 2, &#39;&#39;, 3, &#39;a&#39;, &#39;e&#39; * 23, NaN, &#39;s&#39;, 34])  //[ 1, 2, 3, &#39;a&#39;, &#39;s&#39;, 34 ]

40.短路运算

||&#xff08;或&#xff09;

const flag &#61; false || true //true
// 某个值为假时可以给默认值
const arr &#61; false || []

&&&#xff08;与&#xff09;

const flag1 &#61; false && true //false
const flag2 &#61; true && true //true

41.switch 简写

可以用对象替代switch&#xff0c;提高代码可读性

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

结语

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

回复 【idea激活】即可获得idea的激活方式

回复 【Java】获取java相关的视频教程和资料

回复 【SpringCloud】获取SpringCloud相关多的学习资料

回复 【python】获取全套0基础Python知识手册

回复 【2020】获取2020java相关面试题教程

回复 【加群】即可加入终端研发部相关的技术交流群

最近于哥也在搞视频号啦&#xff0c;主要针对于程序员方向的&#xff0c;大家可以去关注一波&#xff1a;

最近面试Java后端开发的感受

互联网的圈子&#xff0c;游戏行业的现状是如何&#xff1f;

动画&#xff1a;一招学会TCP的三次握手和四次挥手

干掉PostMan&#xff01;IDEA这款插件太实用了…

美团面试题&#xff1a;Java-线程池 ThreadPool 专题详解

当去阿里面试 Java 都是问什么?

Linux 最常用命令&#xff08;简单易学&#xff0c;但能解决 95% 以上的问题&#xff09;

相信自己&#xff0c;没有做不到的&#xff0c;只有想不到的

在这里获得的不仅仅是技术&#xff01;

喜欢就给个“在看


推荐阅读
  • POJ1942   DPaths on a Grid
    Imagineyouareattendingyourmathlessonatschool.Onceagain,youareboredbecauseyourteachertellst ... [详细]
  • 微信小程序中如何获取当前位置经纬度以及地图显示
    小编给大家分享一下微信小程序中如何获取当前位置经纬度以及地图显示,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅 ... [详细]
  • 题目描述ZZH是北化acm界新生代的大佬,每天会和无数来自全球各地的大佬进行交流。但是,ZZH每天水群的时间有限。ZZH想尽可能多的和更强的大佬进行交 ... [详细]
  • 【Linux系统编程:基础IO 下】dup2 实现输出重定向、输入重定向、追加重定向 | 理解磁盘 | 理解文件系统中inode的概念 | 软硬链接
    写在前面这里先接着《基础IO上》中的缓冲区的内容作些补充,这里主要补充dup2接口。✔测试用例一:#include#inclu ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 开发笔记:dice
    本文由编程笔记#小编为大家整理,主要介绍了dice相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 利用JavaScript的函数有两种方式1.jQueryjQuery.inArray(value,array[,fromIndex])value类型: Anything要查找的值。 ... [详细]
  • 近期因为内部培训有序列化的需求,于是趁此机会由浅入深的剖析一下序列化相关内容。之前也写过由浅入深的xml漏洞系列,欢迎阅读:https:skysec.top20180817浅析xml及其安全问题 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
author-avatar
林嘉文志鸿圣文
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有