哥伦布

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

 



posted @   南柯Dream丶  阅读(200)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示