JS开发必须知道的41个技巧
1.数组交集
普通数组
1 const arr1 = [1, 2, 3, 4, 5, 8, 9], arr2 = [5, 6, 7, 8, 9]; 2 const intersection = arr1.filter(val => arr2.indexOf(val) > -1) 3 console.log(intersection) //[5, 8, 9]
数组对象
数组对象目前仅针对value值为简单的Number,String,Boolan数据类型 文中JSON.stringif比较对象是简写方法,完整的对象比较请看技巧24.对象是否相等
1 const arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }, { name: 'name5', id: 5 }]; 2 const arr2 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }]; 3 const result = arr2.filter((v) => arr1.some(n => JSON.stringify(n) === JSON.stringify(v))) 4 console.log(result); // [{ name: 'name1', id: 1 },{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name5', id: 5 }]
2.数组并集
普通数组
1 const arr1 = [1, 2, 3, 4, 5, 8, 9] 2 const arr2 = [5, 6, 7, 8, 9]; 3 const result = arr1.concat(arr2.filter(v => !arr1.includes(v))) 4 console.log(result) //[1, 2, 3, 4, 5, 8, 9, 6, 7]
数组对象
1 const arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }]; 2 const arr2 = [{ name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }]; 3 let arr3 = arr1.concat(arr2); 4 let result = []; 5 let obj = []; 6 result = arr3.reduce((prev, cur, index, arr) => { 7 obj[cur.id] ? '' : obj[cur.id] = true && prev.push(cur); 8 return prev; 9 }, []); 10 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所没有的
普通数组
1 const arr1 = [1, 2, 3, 4, 5, 8, 9] 2 const arr2 = [5, 6, 7, 8, 9]; 3 const diff = arr1.filter(item => !new Set(arr2).has(item)) 4 console.log(diff) //[ 1, 2, 3, 4 ]
数组对象
1 let arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }]; 2 let arr2 = [{ name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }]; 3 let result = arr1.filter((v) => arr2.every(n => JSON.stringify(n) !== JSON.stringify(v))) 4 console.log(result); // [ { name: 'name2', id: 2 }, { name: 'name3', id: 3 } ]
4.数组补集
两个数组各自没有的集合
普通数组
1 const arr1 = [1, 2, 3, 4, 5, 8, 9] 2 const arr2 = [5, 6, 7, 8, 9]; 3 const difference = Array.from(new Set(arr1.concat(arr2).filter(v => !new Set(arr1).has(v) || !new Set(arr2).has(v)))) 4 console.log(difference) //[ 1, 2, 3, 4, 6, 7 ]
数组对象
1 let arr1 = [{ name: 'name1', id: 1 }, { name: 'name2', id: 2 }, { name: 'name3', id: 3 }]; 2 let arr2 = [{ name: 'name1', id: 1 }, { name: 'name4', id: 4 }, { name: 'name5', id: 5 }]; 3 let arr3 = arr1.concat(arr2); 4 let result = arr3.filter((v) =>arr1.every(n => JSON.stringify(n) !== JSON.stringify(v)) || arr2.every(n => JSON.stringify(n) !== JSON.stringify(v))) 5 console.log(result); // [{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name4', id: 4 },{ name: 'name5', id: 5 }]
总结一下,差集就是数组arr1相对于arr2所没有的集合,补集是两个数组各自没有的集合
5.数组去重
普通数组
1 console.log(Array.from(new Set([1, 2, 3, 3, 4, 4]))) //[1,2,3,4] 2 console.log([...new Set([1, 2, 3, 3, 4, 4])]) //[1,2,3,4]
数组对象
1 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 }]; 2 const result = []; 3 arr.forEach(item => { 4 !result.some(v => JSON.stringify(v) === JSON.stringify(item)) && result.push(item) 5 }) 6 console.log(result) //[{ name: 'name1', id: 1 },{ name: 'name2', id: 2 },{ name: 'name3', id: 3 },{ name: 'name4', id: 4 },{ name: 'name5', id: 5 }]
6.数组排序
普通数组
1 console.log([1, 2, 3, 4].sort((a, b) => a - b)); // [1, 2,3,4] 升序 2 console.log([1, 2, 3, 4].sort((a, b) => b - a)); // [4,3,2,1] 降序
数组对象
1 const arr1 = [{ name: "Rom", age: 12 }, { name: "Bob", age: 22 }].sort((a, b) => { return a.age - b.age })//升序 2 const arr2 = [{ name: "Rom", age: 12 }, { name: "Bob", age: 22 }].sort((a, b) => { return -a.age + b.age })//降序 3 console.log(arr2) // [{ name: 'Bob', age:22 }, { name: 'Rom', age: 12 }] 4 console.log(arr1) // [ { name: 'Rom', age: 12 }, { name: 'Bob', age: 22 } ] 5 两个种类型数组都可以使用sort排序,sort是浏览器内置方法; 6 默认是升序排序,默认返回一个函数,有两个参数: 7 (a, b) => a - b 是升序; 8 (a, b) => b - a 是降序。
7.最大值
普通数组
1 Math.max(...[1, 2, 3, 4]) //4 2 Math.max.apply(this, [1, 2, 3, 4]) //4 3 [1, 2, 3, 4].reduce((prev, cur, curIndex, arr) => { 4 return Math.max(prev, cur); 5 }, 0) //4
取数组对象中id的最大值
1 const arr = [{ id: 1, name: 'jack' }, { id: 2, name: 'may' }, { id: 3, name: 'shawn' }, { id: 4, name: 'tony' }] 2 const arr1 = Math.max.apply(Math, arr.map(item => { return item.id })) 3 const arr2 = arr.sort((a, b) => { return b.id - a.id })[0].id 4 console.log(arr1) // 4 5 console.log(arr2) // 4
8.数组求和
普通数组
1 [1, 2, 3, 4].reduce(function (prev, cur) { 2 return prev + cur; 3 }, 0) //10
数组对象
1 const sum = [{ age: 1 }, { age: 2 }].reduce(function (prev, cur) { 2 return prev + cur.age; 3 }, 0) //3 4 console.log(sum)
9.数组合并
普通数组
1 const arr1 = [1, 2, 3, 4].concat([5, 6]) //[1,2,3,4,5,6] 2 const arr2 = [...[1, 2, 3, 4], ...[4, 5]] //[1,2,3,4,5,6] 3 const arrA = [1, 2], arrB = [3, 4] 4 const arr3 = [].concat.apply(arrA, arrB)//arrA值为[1,2,3,4]
数组对象
1 const arr4 = [{ age: 1 }].concat([{ age: 2 }]) 2 const arr5 = [...[{ age: 1 }], ...[{ age: 2 }]] 3 console.log(arr4) //[ { age: 1 }, { age: 2 } ] 4 console.log(arr5) // [ { age: 1 }, { age: 2 } ]
10.数组是否包含值
普通数组
1 console.log([1, 2, 3].includes(4)) //false 2 console.log([1, 2, 3].indexOf(4)) //-1 如果存在换回索引 3 console.log([1, 2, 3].find((item) => item === 3)) //3 如果数组中无值返回undefined 4 console.log([1, 2, 3].findIndex((item) => item === 3)) //2 如果数组中无值返回-1
数组对象
1 const flag = [{ age: 1 }, { age: 2 }].some(v => JSON.stringify(v) === JSON.stringify({ age: 2 })) 2 console.log(flag)
11.数组每一项都满足
普通数组
1 [1, 2, 3].every(item => { return item > 2 })
数组对象
1 const arr = [{ age: 3 }, { age: 4 }, { age: 5 }] 2 arr.every(item => { return item.age > 2 }) // true
12.数组有一项满足
普通数组
1 [1, 2, 3].some(item => { return item > 2 })
数组对象
1 const arr = [{ age: 3 }, { age: 4 }, { age: 5 }] 2 arr.some(item => { return item.age < 4 }) // true
13.版本号排序
方法一
1 function sortNumber(a, b) { 2 return a - b 3 } 4 const b = [1, 2, 3, 7, 5, 6] 5 const a = ["1.5", "1.5", "1.40", "1.25", "1.1000", "1.1"]; 6 console.log(a.sort(sortNumber)); // [ 1, 2, 3, 5, 6, 7 ] 7 console.log(b.sort(sortNumber)); //[ '1.1000', '1.1', '1.25', '1.40', '1.5', '1.5' ] 8 可见sort排序对整数可以,类似版本号这个格式就不适用了,因为sort函数在比较字符串的时候,是比较字符串的Unicode进行排序的。
方法二
1 //假定字符串的每节数都在5位以下 2 //去除数组空值||空格 3 if (!Array.prototype.trim) { 4 Array.prototype.trim = () => { 5 let arr = []; this.forEach( (e)=> { 6 if (e.match(/\S+/)) arr.push(e); 7 }) 8 return arr; 9 } 10 } 11 12 //提取数字部分 13 function toNum(a) { 14 let d = a.toString(); 15 let c = d.split(/\D/).trim(); 16 let num_place = ["", "0", "00", "000", "0000"], r = num_place.reverse(); 17 for (let i = 0; i < c.length; i++) { 18 let len = c[i].length; 19 c[i] = r[len] + c[i]; 20 } 21 let res = c.join(''); 22 return res; 23 } 24 25 //提取字符 26 function toChar(a) { 27 let d = a.toString(); 28 let c = d.split(/\.|\d/).join(''); 29 return c; 30 } 31 32 function sortVersions(a, b) { 33 let _a1 = toNum(a), _b1 = toNum(b); 34 if (_a1 !== _b1) return _a1 - _b1; 35 else { 36 _a2 = toChar(a).charCodeAt(0).toString(16); 37 _b2 = toChar(b).charCodeAt(0).toString(16); 38 return _a2 - _b2; 39 } 40 } 41 42 let arr1 = ["10", "5", "40", "25", "1000", "1"]; 43 let arr2 = ["1.10", "1.5", "1.40", "1.25", "1.1000", "1.1"]; 44 let arr3 = ["1.10c", "1.10b", "1.10C", "1.25", "1.1000", "1.10A"]; 45 console.log(arr1.sort(sortVersions)) //[ '1', '5', '10', '25', '40', '1000' ] 46 console.log(arr2.sort(sortVersions)) //[ '1.1', '1.5', '1.10', '1.25', '1.40', '1.1000' ] 47 console.log(arr3.sort(sortVersions)) // [ '1.10A', '1.10C', '1.10b', '1.10c', '1.25', '1.1000' ] 48 49 可以看出这个函数均兼容整数,非整数,字母; 50 字母排序是根据Unicode排序的,所以1.10b在1.10C的后面
14. 对象转数组
将数组的key和value转化成数组
1 Object.keys({ name: '张三', age: 14 }) //['name','age'] 2 Object.values({ name: '张三', age: 14 }) //['张三',14] 3 Object.entries({ name: '张三', age: 14 }) //[[name,'张三'],[age,14]] 4 Object.fromEntries([name, '张三'], [age, 14]) //ES10的api,Chrome不支持 , firebox输出{name:'张三',age:14}
15.数组转对象
将数组的值转化为对象的value
1 const arrName = ['张三', '李四', '王五'] 2 const arrAge = ['20', '30', '40'] 3 const arrDec = ['描述1', '描述2', '描述3'] 4 const obj = arrName.map((item, index) => { 5 return { name: item, age: arrAge[index], dec: arrDec[index] } 6 }) 7 console.log(obj) // [{ name: '张三', age: '20', dec: '描述1' },{ name: '李四', age: '30', dec: '描述2' },{ name: '王五', age: '40', dec: '描述3' }]
16.数组解构
1 const arr = [1, 2]; //后面一定要加分号,因为不加解释器会认为在读数组 2 [arr[1], arr[0]] = [arr[0], arr[1]]; // [2,1]
17.对象变量属性
1 const flag = true; 2 const obj = { 3 a: 0, 4 [flag ? "c" : "d"]: 2 5 }; 6 // obj => { a: 0, c: 2 }
18.对象多余属性删除
1 const { name, age, ...obj } = { name: '张三', age: 13, dec: '描述1', info: '信息' } 2 console.log(name) // 张三 3 console.log(age) // 13 4 console.log(obj) // {dec: '描述1', info: '信息' }
19.对象嵌套属性解构
1 const { info: { dec } } = { name: '张三', age: 13, info: { dec: '描述1', info: '信息' } } 2 console.log(dec) // 描述1
20.解构对象属性别名
1 const { name: newName } = { name: '张三', age: 13 } 2 console.log(newName) // 张三
21.解构对象属性默认值
1 const { dec = '这是默认dec值' } = { name: '张三', age: 13 } 2 console.log(dec) //这是默认dec值
22.拦截对象
利用Object.defineProperty拦截对象
无法拦截数组的值
1 let obj = { name: '', age: '', sex: '' }, 2 defaultName = ["这是姓名默认值1", "这是年龄默认值1", "这是性别默认值1"]; 3 Object.keys(obj).forEach(key => { 4 Object.defineProperty(obj, key, { // 拦截整个object 对象,并通过get获取值,set设置值,vue 2.x的核心就是这个来监听 5 get() { 6 return defaultName; 7 }, 8 set(value) { 9 defaultName = value; 10 } 11 }); 12 }); 13 14 console.log(obj.name); // [ '这是姓名默认值1', '这是年龄默认值1', '这是性别默认值1' ] 15 console.log(obj.age); // [ '这是姓名默认值1', '这是年龄默认值1', '这是性别默认值1' ] 16 console.log(obj.sex); // [ '这是姓名默认值1', '这是年龄默认值1', '这是性别默认值1' ] 17 obj.name = "这是改变值1"; 18 console.log(obj.name); // 这是改变值1 19 console.log(obj.age); // 这是改变值1 20 console.log(obj.sex); // 这是改变值1 21 22 let objOne = {}, defaultNameOne = "这是默认值2"; 23 Object.defineProperty(obj, 'name', { 24 get() { 25 return defaultNameOne; 26 }, 27 set(value) { 28 defaultNameOne = value; 29 } 30 }); 31 console.log(objOne.name); // undefined 32 objOne.name = "这是改变值2"; 33 console.log(objOne.name); // 这是改变值2 34 利用proxy拦截对象 35 36 let obj = { name: '', age: '', sex: '' } 37 let handler = { 38 get(target, key, receiver) { 39 console.log("get", key); 40 return Reflect.get(target, key, receiver); 41 }, 42 set(target, key, value, receiver) { 43 console.log("set", key, value); // set name 李四 // set age 24 44 return Reflect.set(target, key, value, receiver); 45 } 46 }; 47 let proxy = new Proxy(obj, handler); 48 proxy.name = "李四"; 49 proxy.age = 24; 50 defineProterty和proxy的对比: 51 1.defineProterty是es5的标准, proxy是es6的标准; 52 2.proxy可以监听到数组索引赋值, 改变数组长度的变化; 53 3.proxy是监听对象, 不用深层遍历, defineProterty是监听属性; 54 4.利用defineProterty实现双向数据绑定(vue2.x采用的核心)
23.对象深度拷贝
1 JSON.stringify深度克隆对象; 2 1.无法对函数 、RegExp等特殊对象的克隆; 3 2.会抛弃对象的constructor, 所有的构造函数会指向Object; 4 3.对象有循环引用, 会报错 5 6 const mapTag = '[object Map]'; 7 const setTag = '[object Set]'; 8 const arrayTag = '[object Array]'; 9 const objectTag = '[object Object]'; 10 const argsTag = '[object Arguments]'; 11 12 const boolTag = '[object Boolean]'; 13 const dateTag = '[object Date]'; 14 const numberTag = '[object Number]'; 15 const stringTag = '[object String]'; 16 const symbolTag = '[object Symbol]'; 17 const errorTag = '[object Error]'; 18 const regexpTag = '[object RegExp]'; 19 const funcTag = '[object Function]'; 20 21 const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag]; 22 23 24 function forEach(array, iteratee) { 25 let index = -1; 26 const length = array.length; 27 while (++index < length) { 28 iteratee(array[index], index); 29 } 30 return array; 31 } 32 33 function isObject(target) { 34 const type = typeof target; 35 return target !== null && (type === 'object' || type === 'function'); 36 } 37 38 function getType(target) { 39 return Object.prototype.toString.call(target); 40 } 41 42 function getInit(target) { 43 const Ctor = target.constructor; 44 return new Ctor(); 45 } 46 47 function cloneSymbol(targe) { 48 return Object(Symbol.prototype.valueOf.call(targe)); 49 } 50 51 function cloneReg(targe) { 52 const reFlags = /\w*$/; 53 const result = new targe.constructor(targe.source, reFlags.exec(targe)); 54 result.lastIndex = targe.lastIndex; 55 return result; 56 } 57 58 function cloneFunction(func) { 59 const bodyReg = /(?<={)(.|\n)+(?=})/m; 60 const paramReg = /(?<=\().+(?=\)\s+{)/; 61 const funcString = func.toString(); 62 if (func.prototype) { 63 const param = paramReg.exec(funcString); 64 const body = bodyReg.exec(funcString); 65 if (body) { 66 if (param) { 67 const paramArr = param[0].split(','); 68 return new Function(...paramArr, body[0]); 69 } else { 70 return new Function(body[0]); 71 } 72 } else { 73 return null; 74 } 75 } else { 76 return eval(funcString); 77 } 78 } 79 80 function cloneOtherType(targe, type) { 81 const Ctor = targe.constructor; 82 switch (type) { 83 case boolTag: 84 case numberTag: 85 case stringTag: 86 case errorTag: 87 case dateTag: 88 return new Ctor(targe); 89 case regexpTag: 90 return cloneReg(targe); 91 case symbolTag: 92 return cloneSymbol(targe); 93 case funcTag: 94 return cloneFunction(targe); 95 default: 96 return null; 97 } 98 } 99 100 function clone(target, map = new WeakMap()) { 101 102 // 克隆原始类型 103 if (!isObject(target)) { 104 return target; 105 } 106 107 // 初始化 108 const type = getType(target); 109 let cloneTarget; 110 if (deepTag.includes(type)) { 111 cloneTarget = getInit(target, type); 112 } else { 113 return cloneOtherType(target, type); 114 } 115 116 // 防止循环引用 117 if (map.get(target)) { 118 return map.get(target); 119 } 120 map.set(target, cloneTarget); 121 122 // 克隆set 123 if (type === setTag) { 124 target.forEach(value => { 125 cloneTarget.add(clone(value, map)); 126 }); 127 return cloneTarget; 128 } 129 130 // 克隆map 131 if (type === mapTag) { 132 target.forEach((value, key) => { 133 cloneTarget.set(key, clone(value, map)); 134 }); 135 return cloneTarget; 136 } 137 138 // 克隆对象和数组 139 const keys = type === arrayTag ? undefined : Object.keys(target); 140 forEach(keys || target, (value, key) => { 141 if (keys) { 142 key = value; 143 } 144 cloneTarget[key] = clone(target[key], map); 145 }); 146 147 return cloneTarget; 148 } 149 150 console.log(clone({ 151 name: '张三', age: 23, 152 obj: { name: '李四', age: 46 }, 153 arr: [1, 2, 3] 154 })) // { name: '张三', age: 23, obj: { name: '李四', age: 46 }, arr: [ 1, 2, 3 ] } 155 对象深度克隆实际上就是要兼容Array,RegExp,Date,Function类型; 156 克隆函数可以用正则取出函数体和参数,再定义一个函数将取出来的值赋值进去 157 详细请戳对象深度拷贝
24.对象是否相等
1 如果用JSON.stringify转化属性顺序不同,也不相等; 2 而且不支持无法对函数 、RegExp等特殊对象的克隆 3 4 function deepCompare(x, y) { 5 var i, l, leftChain, rightChain; 6 7 function compare2Objects(x, y) { 8 var p; 9 10 // remember that NaN === NaN returns false 11 // and isNaN(undefined) returns true 12 if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { 13 return true; 14 } 15 16 // Compare primitives and functions. 17 // Check if both arguments link to the same object. 18 // Especially useful on the step where we compare prototypes 19 if (x === y) { 20 return true; 21 } 22 23 // Works in case when functions are created in constructor. 24 // Comparing dates is a common scenario. Another built-ins? 25 // We can even handle functions passed across iframes 26 if ((typeof x === 'function' && typeof y === 'function') || 27 (x instanceof Date && y instanceof Date) || 28 (x instanceof RegExp && y instanceof RegExp) || 29 (x instanceof String && y instanceof String) || 30 (x instanceof Number && y instanceof Number)) { 31 return x.toString() === y.toString(); 32 } 33 34 // At last checking prototypes as good as we can 35 if (!(x instanceof Object && y instanceof Object)) { 36 return false; 37 } 38 39 if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) { 40 return false; 41 } 42 43 if (x.constructor !== y.constructor) { 44 return false; 45 } 46 47 if (x.prototype !== y.prototype) { 48 return false; 49 } 50 51 // Check for infinitive linking loops 52 if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { 53 return false; 54 } 55 56 // Quick checking of one object being a subset of another. 57 // todo: cache the structure of arguments[0] for performance 58 for (p in y) { 59 if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { 60 return false; 61 } else if (typeof y[p] !== typeof x[p]) { 62 return false; 63 } 64 } 65 66 for (p in x) { 67 if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { 68 return false; 69 } else if (typeof y[p] !== typeof x[p]) { 70 return false; 71 } 72 73 switch (typeof (x[p])) { 74 case 'object': 75 case 'function': 76 77 leftChain.push(x); 78 rightChain.push(y); 79 80 if (!compare2Objects(x[p], y[p])) { 81 return false; 82 } 83 84 leftChain.pop(); 85 rightChain.pop(); 86 break; 87 88 default: 89 if (x[p] !== y[p]) { 90 return false; 91 } 92 break; 93 } 94 } 95 96 return true; 97 } 98 99 if (arguments.length < 1) { 100 return true; 101 } 102 103 for (i = 1, l = arguments.length; i < l; i++) { 104 105 leftChain = []; //Todo: this can be cached 106 rightChain = []; 107 108 if (!compare2Objects(arguments[0], arguments[i])) { 109 return false; 110 } 111 } 112 113 return true; 114 } 115 116 const obj1 = { 117 name: '张三', age: 23, 118 obj: { name: '李四', age: 46 }, 119 arr: [1, 2, 3], 120 date: new Date(23), 121 reg: new RegExp('abc'), 122 fun: () => { } 123 } 124 const obj2 = { 125 name: '张三', age: 23, 126 obj: { name: '李四', age: 46 }, 127 arr: [1, 2, 3], 128 date: new Date(23), 129 reg: new RegExp('abc'), 130 fun: () => { } 131 } 132 133 console.log(deepCompare(obj1, obj2)) // true 134 135 判断对象是否相等,实际上就是要处理Array,Date,RegExp,Object,Function的特殊类型是否相等
25.对象转化为字符串
1 通过字符串 + Object 的方式来转化对象为字符串(实际上是调用.toString() 方法) 2 3 'the Math object:' + Math.ceil(3.4) // "the Math object:4" 4 'the JSON object:' + { name: '曹操' } // "the JSON object:[object Object]" 5 覆盖对象的toString和valueOf方法来自定义对象的类型转换 6 7 2 * { valueOf: () => '4' } // 8 8 'J' + { toString: () => 'ava' } // "Java" 9 当 + 用在连接字符串时,当一个对象既有toString方法又有valueOf方法时候,JS通过盲目使用valueOf方法来解决这种含糊; 10 对象通过valueOf方法强制转换为数字,通过toString方法强制转换为字符串 11 12 '' + { toString: () => 'S', valueOf: () => 'J' } //J
26.函数隐式返回值
1 (() => 3)() //3 2 (() => (3))() 3 函数省略大括号,或者将大括号改成小括号可以确保代码以单个语句的形式进行求值
27.函数自执行
1 const Func = function () { }(); // 常用 2 3 (function () { })(); // 常用 4 (function () { }()); // 常用 5 [function () { }()]; 6 7 new function () { }; 8 new function () { }(); 9 void function () { }(); 10 typeof function () { }(); 11 delete function () { }(); 12 13 + function () { }(); 14 - function () { }(); 15 ~ function () { }(); 16 ! function () { }();
28.函数异步执行
1 Promise 2 3 Promise.reject('这是第二个 reject 值').then((data) => { 4 console.log(data) 5 }).catch(data => { 6 console.log(data) //这是第二个 reject 值 7 }) 8 Generator 9 10 function* gen(x) { 11 const y = yield x + 6; 12 return y; 13 } 14 15 // yield 如果用在另外一个表达式中,要放在()里面 16 // 像上面如果是在=右边就不用加() 17 function* genOne(x) { 18 const y = `这是第一个 yield 执行:${yield x + 1}`; 19 return y; 20 } 21 22 const g = gen(1); 23 //执行 Generator 会返回一个Object,而不是像普通函数返回return 后面的值 24 g.next() // { value: 7, done: false } 25 //调用指针的 next 方法,会从函数的头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式或return语句暂停,也就是执行yield 这一行 26 // 执行完成会返回一个 Object, 27 // value 就是执行 yield 后面的值,done 表示函数是否执行完毕 28 g.next() // { value: undefined, done: true } 29 // 因为最后一行 return y 被执行完成,所以done 为 true 30 Async / Await 31 32 function getSomething() { 33 return "something"; 34 } 35 async function testAsync() { 36 return Promise.resolve("hello async"); 37 } 38 async function test() { 39 const v1 = await getSomething(); 40 const v2 = await testAsync(); 41 console.log(v1, v2); //something 和 hello async 42 } 43 test(); 44 String
29.字符串翻转
1 function reverseStr(str = "") { 2 return str.split("").reduceRight((t, v) => t + v); 3 } 4 5 const str = "reduce123"; 6 console.log(reverseStr(str)); // "321recuder"
30.url参数序列化
1 将对象序列化成url参数传递 2 function stringifyUrl(search = {}) { 3 return Object.entries(search).reduce( 4 (t, v) => `${t}${v[0]}=${encodeURIComponent(v[1])}&`, 5 Object.keys(search).length ? "?" : "" 6 ).replace(/&$/, ""); 7 } 8 9 console.log(stringifyUrl({ age: 27, name: "YZW" })); // "?age=27&name=YZW"
31.url参数反序列化
1 一般会通过location.search拿到路由传递的参数,并进行反序列化得到对象 2 3 function parseUrlSearch() { 4 const search = '?age=25&name=TYJ' 5 return search.replace(/(^\?)|(&$)/g, "").split("&").reduce((t, v) => { 6 const [key, val] = v.split("="); 7 t[key] = decodeURIComponent(val); 8 return t; 9 }, {}); 10 } 11 12 console.log(parseUrlSearch()); // { age: "25", name: "TYJ" }
32.转化为字符串
1 const val = 1 + ""; // 通过+ ''空字符串转化 2 console.log(val); // "1" 3 console.log(typeof val); // "string" 4 5 const val1 = String(1); 6 console.log(val1); // "1" 7 console.log(typeof val1); // "string" 8 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"
1 方法二 2 3 console.log('1234567890'.replace(/\B(?=(\d{3})+(?!\d))/g, ",")) 4 console.log((1234567890).toLocaleString())
34.字符串转数字
1 方法一 2 用 * 1来转化为数字, 实际上是调用.valueOf方法 3 4 '32' * 1 // 32 5 'ds' * 1 // NaN 6 null * 1 // 0 7 undefined * 1 // NaN 8 1 * { valueOf: () => '3' } // 3
1 方法二 2 3 + '123' // 123 4 + 'ds' // NaN 5 + '' // 0 6 + null // 0 7 + undefined // NaN 8 + { valueOf: () => '3' } // 3
35.判断小数是否相等
1 肯定有人会说这还不简单,直接用'==='比较; 2 实际上0.1 + 0.2 !== 0.3,因为计算机不能精确表示0.1, 0.2这样的浮点数,所以相加就不是0.3了 3 4 Number.EPSILON = (function () { //解决兼容性问题 5 return Number.EPSILON ? Number.EPSILON : Math.pow(2, -52); 6 })(); 7 //上面是一个自调用函数,当JS文件刚加载到内存中,就会去判断并返回一个结果 8 function numbersequal(a, b) { 9 return Math.abs(a - b) < Number.EPSILON; 10 } 11 //接下来再判断 12 const a = 0.1 + 0.2, b = 0.3; 13 console.log(numbersequal(a, b)); //这里就为true了
36.双位运算符
1 双位运算符比Math.floor(), Math.ceil()速度快 2 3 ~~7.5 // 7 4 Math.ceil(7.5) // 8 5 Math.floor(7.5) // 7 6 7 8 ~~-7.5 // -7 9 Math.floor(-7.5) // -8 10 Math.ceil(-7.5) // -7 11 所以负数时,双位运算符和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.判断数据类型
1 function dataTypeJudge(val, type) { 2 const dataType = Object.prototype.toString.call(val).replace(/\[object (\w+)\]/, "$1").toLowerCase(); 3 return type ? dataType === type : dataType; 4 } 5 console.log(dataTypeJudge("young")); // "string" 6 console.log(dataTypeJudge(20190214)); // "number" 7 console.log(dataTypeJudge(true)); // "boolean" 8 console.log(dataTypeJudge([], "array")); // true 9 console.log(dataTypeJudge({}, "array")); // false 10 可判断类型:undefined、null、string、number、boolean、array、object、symbol、date、regexp、function、asyncfunction、arguments、set、map、weakset、weakmap
39.使用Boolean过滤数组假值
1 const compact = arr => arr.filter(Boolean) 2 compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]) //[ 1, 2, 3, 'a', 's', 34 ]
40.短路运算
1 ||(或) 2 3 const flag = false || true //true 4 // 某个值为假时可以给默认值 5 const arr = false || [] 6 &&(与) 7 8 const flag1 = false && true //false 9 const flag2 = true && true //true
41.switch 简写
1 const obj = { 2 '张三': 'age12', 3 '李四': 'age120', 4 } 5 console.log(obj['张三'])
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗