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
候補:
將二維數組轉換為一維數組
const arr=[[1,2,3],[3,4],[5]];
console.log([].concat.apply([],arr));
//1這個就是apply的一個巧妙的用處,可以將一個數組默認的轉換為一個參數列表
//([param1,param2,param3] 轉換為 param1,param2,param3) 這個如果讓我們用程序來實現將數
//組的每一個項,來裝換為參數的列表,可能都得費一會功夫,借助apply的這點特性,所以就有了以下
//高效率的方法
//2 此時 apply 為我們把 arr 去掉一個中括號 得到里面的索引 在用concat 去拼接數組 就搞定啦
————————————————
Ev.小強」的原創文章
原文鏈接:https://blog.csdn.net/u011397539/article/details/82382500
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數據類型 文中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 => { 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的后面
- 對象轉數組
將數組的key和value轉化成數組
Object.keys({ name: '張三', age: 14 }) //['name','age']
Object.values({ name: '張三', age: 14 }) //['張三',14]
Object.entries({ name: '張三', age: 14 }) //[[name,'張三'],[age,14]]
Object.fromEntries([name, '張三'], [age, 14]) //ES10的api,Chrome不支持 , firebox輸出{name:'張三',age:14}
15.數組轉對象
將數組的值轉化為對象的value
const arrName = ['張三', '李四', '王五']
const arrAge=['20','30','40']
const arrDec = ['描述1', '描述2', '描述3']
const obj = arrName.map((item,index)=>{
return { name: item, age: arrAge[index],dec:arrDec[index]}
})
console.log(obj) // [{ name: '張三', age: '20', dec: '描述1' },{ name: '李四', age: '30', dec: '描述2' },{ name: '王五', age: '40', dec: '描述3' }]
16.數組解構
const arr=[1,2]; //后面一定要加分號,因為不加解釋器會認為在讀數組
[arr[1], arr[0]] = [arr[0], arr[1]]; // [2,1]
Object
17.對象變量屬性
const flag = true;
const obj = {
a: 0,
[flag ? "c" : "d"]: 2
};
// obj => { a: 0, c: 2 }
18.對象多余屬性刪除
const { name, age, ...obj } = { name: '張三', age: 13, dec: '描述1', info: '信息' }
console.log(name) // 張三
console.log(age) // 13
console.log(obj) // {dec: '描述1', info: '信息' }
19.對象嵌套屬性解構
const { info:{ dec} } = { name: '張三', age: 13, info:{dec: '描述1', info: '信息' }}
console.log(dec) // 描述1
20.解構對象屬性別名
const { name:newName } = { name: '張三', age: 13 }
console.log(newName) // 張三
21.解構對象屬性默認值
const { dec='這是默認dec值' } = { name: '張三', age: 13 }
console.log(dec) //這是默認dec值
22.攔截對象
利用Object.defineProperty攔截對象
無法攔截數組的值
let obj = { name: '', age: '', sex: '' },
defaultName = ["這是姓名默認值1", "這是年齡默認值1", "這是性別默認值1"];
Object.keys(obj).forEach(key => {
Object.defineProperty(obj, key, {
// 攔截整個object 對象,并通過get獲取值,set設置值,vue 2.x的核心就是這個來監聽
get() {
return defaultName;
},
set(value) {
defaultName = value;
}
});
});
console.log(obj.name); // [ '這是姓名默認值1', '這是年齡默認值1', '這是性別默認值1' ]
console.log(obj.age); // [ '這是姓名默認值1', '這是年齡默認值1', '這是性別默認值1' ]
console.log(obj.sex); // [ '這是姓名默認值1', '這是年齡默認值1', '這是性別默認值1' ]
obj.name = "這是改變值1";
console.log(obj.name); // 這是改變值1
console.log(obj.age); // 這是改變值1
console.log(obj.sex); // 這是改變值1
let objOne = {}, defaultNameOne = "這是默認值2";
Object.defineProperty(obj, 'name', {
get() {
return defaultNameOne;
},
set(value) {
defaultNameOne = value;
}
});
console.log(objOne.name); // undefined
objOne.name = "這是改變值2";
console.log(objOne.name); // 這是改變值2
利用proxy攔截對象
let obj = { name: '', age: '', sex: '' }
let handler = {
get(target, key, receiver) {
console.log("get", key);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("set", key, value); // set name 李四 // set age 24
return Reflect.set(target, key, value, receiver);
}
};
let proxy = new Proxy(obj, handler);
proxy.name = "李四";
proxy.age = 24;
defineProterty和proxy的對比:
1.defineProterty是es5的標準,proxy是es6的標準;
2.proxy可以監聽到數組索引賦值,改變數組長度的變化;
3.proxy是監聽對象,不用深層遍歷,defineProterty是監聽屬性;
4.利用defineProterty實現雙向數據綁定(vue2.x采用的核心)
23.對象深度拷貝
JSON.stringify深度克隆對象;
1.無法對函數 、RegExp等特殊對象的克隆;
2.會拋棄對象的constructor,所有的構造函數會指向Object;
3.對象有循環引用,會報錯
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';
const argsTag = '[object Arguments]';
const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';
const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];
function forEach(array, iteratee) {
let index = -1;
const length = array.length;
while (++index < length) {
iteratee(array[index], index);
}
return array;
}
function isObject(target) {
const type = typeof target;
return target !== null && (type === 'object' || type === 'function');
}
function getType(target) {
return Object.prototype.toString.call(target);
}
function getInit(target) {
const Ctor = target.constructor;
return new Ctor();
}
function cloneSymbol(targe) {
return Object(Symbol.prototype.valueOf.call(targe));
}
function cloneReg(targe) {
const reFlags = /\w*$/;
const result = new targe.constructor(targe.source, reFlags.exec(targe));
result.lastIndex = targe.lastIndex;
return result;
}
function cloneFunction(func) {
const bodyReg = /(?<={)(.|\n)+(?=})/m;
const paramReg = /(?<=\().+(?=\)\s+{)/;
const funcString = func.toString();
if (func.prototype) {
const param = paramReg.exec(funcString);
const body = bodyReg.exec(funcString);
if (body) {
if (param) {
const paramArr = param[0].split(',');
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 = 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 = new WeakMap()) {
// 克隆原始類型
if (!isObject(target)) {
return target;
}
// 初始化
const type = getType(target);
let cloneTarget;
if (deepTag.includes(type)) {
cloneTarget = getInit(target, type);
} else {
return cloneOtherType(target, type);
}
// 防止循環引用
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);
// 克隆set
if (type === setTag) {
target.forEach(value => {
cloneTarget.add(clone(value, map));
});
return cloneTarget;
}
// 克隆map
if (type === mapTag) {
target.forEach((value, key) => {
cloneTarget.set(key, clone(value, map));
});
return cloneTarget;
}
// 克隆對象和數組
const keys = type === arrayTag ? undefined : Object.keys(target);
forEach(keys || target, (value, key) => {
if (keys) {
key = value;
}
cloneTarget[key] = clone(target[key], map);
});
return cloneTarget;
}
console.log(clone({
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)); // "321recuder"
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"
方法二
console.log('1234567890'.replace(/\B(?=(\d{3})+(?!\d))/g, ","))
console.log((1234567890).toLocaleString())
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['張三'])
源碼地址 https://github.com/lanzhsh/react-vue-koa/tree/master/js/skill;