【JS】699- JS開發(fā)必須知道的41個(gè)技巧
JS是前端的核心,但有些使用技巧你還不一定知道;
本文梳理了JS的41個(gè)技巧,幫助大家提高JS的使用技巧;
文章有點(diǎn)長(zhǎng),可以clone下源碼,直接擼,源碼地址 https://github.com/lanzhsh/react-vue-koa/tree/master/js/skill,原創(chuàng)不易,歡迎star;
Array
1.數(shù)組交集
普通數(shù)組
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]
復(fù)制代碼
數(shù)組對(duì)象
數(shù)組對(duì)象目前僅針對(duì)value值為簡(jiǎn)單的Number,String,Boolan數(shù)據(jù)類型 文中JSON.stringif比較對(duì)象是簡(jiǎn)寫方法,完整的對(duì)象比較請(qǐng)看技巧24.對(duì)象是否相等
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?}]
復(fù)制代碼
2.數(shù)組并集
普通數(shù)組
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]
復(fù)制代碼
數(shù)組對(duì)象
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?}]
復(fù)制代碼
3.數(shù)組差集
數(shù)組arr1相對(duì)于arr2所沒有的
普通數(shù)組
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?]
復(fù)制代碼
數(shù)組對(duì)象
//?對(duì)象數(shù)組
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?}?]
復(fù)制代碼
4.數(shù)組補(bǔ)集
兩個(gè)數(shù)組各自沒有的集合
普通數(shù)組
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?]
復(fù)制代碼
數(shù)組對(duì)象
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?}]
復(fù)制代碼
總結(jié)一下,差集就是數(shù)組arr1相對(duì)于arr2所沒有的集合,補(bǔ)集是兩個(gè)數(shù)組各自沒有的集合
5.數(shù)組去重
普通數(shù)組
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]
復(fù)制代碼
數(shù)組對(duì)象
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?}]
復(fù)制代碼
6.數(shù)組排序
普通數(shù)組
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]?降序
復(fù)制代碼
數(shù)組對(duì)象
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?}?]
復(fù)制代碼
兩個(gè)種類型數(shù)組都可以使用sort排序,sort是瀏覽器內(nèi)置方法;
默認(rèn)是升序排序,默認(rèn)返回一個(gè)函數(shù),有兩個(gè)參數(shù):
(a, b) => a - b 是升序;
(a, b) => b - a 是降序。
7.最大值
普通數(shù)組
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
復(fù)制代碼
取數(shù)組對(duì)象中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
復(fù)制代碼
8.數(shù)組求和
普通數(shù)組
[1,?2,?3,?4].reduce(function?(prev,?cur)?{
??return?prev?+?cur;
},?0)?//10?
復(fù)制代碼
數(shù)組對(duì)象
const?sum?=?[{age:1},{age:2}].reduce(function?(prev,?cur)?{
??return?prev?+?cur.age;
},?0)?//3
console.log(sum)
復(fù)制代碼
9.數(shù)組合并
普通數(shù)組
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]
復(fù)制代碼
數(shù)組對(duì)象
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?}?]
復(fù)制代碼
10.數(shù)組是否包含值
普通數(shù)組
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?如果數(shù)組中無值返回undefined
console.log([1,?2,?3].findIndex((item)?=>?item?===?3))?//2?如果數(shù)組中無值返回-1
復(fù)制代碼
數(shù)組對(duì)象
const?flag?=?[{age:1},{age:2}].some(v=>JSON.stringify(v)===JSON.stringify({age:2}))
console.log(flag)
復(fù)制代碼
11.數(shù)組每一項(xiàng)都滿足
普通數(shù)組
[1,?2,?3].every(item?=>?{?return?item?>?2?})
復(fù)制代碼
數(shù)組對(duì)象
const?arr?=?[{?age:?3?},?{?age:?4?},?{?age:?5?}]
arr.every(item?=>?{?return?item.age?>?2?})?//?true
復(fù)制代碼
12.數(shù)組有一項(xiàng)滿足
普通數(shù)組
[1,?2,?3].some(item?=>?{?return?item?>?2?})
復(fù)制代碼
數(shù)組對(duì)象
const?arr?=?[{?age:?3?},?{?age:?4?},?{?age:?5?}]
arr.some(item?=>?{?return?item.age?4?})?//?true
復(fù)制代碼
13.版本號(hào)排序
方法一
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'?]
復(fù)制代碼
可見sort排序?qū)φ麛?shù)可以,類似版本號(hào)這個(gè)格式就不適用了,因?yàn)閟ort函數(shù)在比較字符串的時(shí)候,是比較字符串的Unicode進(jìn)行排序的。
方法二
//假定字符串的每節(jié)數(shù)都在5位以下
//去除數(shù)組空值||空格
if?(!Array.prototype.trim)?{
??Array.prototype.trim?=?function?()?{
????let?arr?=?[];?this.forEach(function?(e)?{
??????if?(e.match(/\S+/))?arr.push(e);
????})
????return?arr;
??}
}
//提取數(shù)字部分
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?????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'?]
復(fù)制代碼
可以看出這個(gè)函數(shù)均兼容整數(shù),非整數(shù),字母;
字母排序是根據(jù)Unicode排序的,所以1.10b在1.10C的后面
14. 對(duì)象轉(zhuǎn)數(shù)組
將數(shù)組的key和value轉(zhuǎn)化成數(shù)組
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}
復(fù)制代碼
15.數(shù)組轉(zhuǎn)對(duì)象
將數(shù)組的值轉(zhuǎn)化為對(duì)象的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'?}]
復(fù)制代碼
16.數(shù)組解構(gòu)
const?arr=[1,2];?//后面一定要加分號(hào),因?yàn)椴患咏忉屍鲿?huì)認(rèn)為在讀數(shù)組
[arr[1],?arr[0]]?=?[arr[0],?arr[1]];?//?[2,1]
復(fù)制代碼
Object
17.對(duì)象變量屬性
const?flag?=?true;
const?obj?=?{
????a:?0,
????[flag???"c"?:?"d"]:?2
};
//?obj?=>?{?a:?0,?c:?2?}
復(fù)制代碼
18.對(duì)象多余屬性刪除
const?{?name,?age,?...obj?}?=?{?name:?'張三',?age:?13,?dec:?'描述1',?info:?'信息'?}
console.log(name)??//?張三
console.log(age)??//?13
console.log(obj)??//?{dec:?'描述1',?info:?'信息'?}
復(fù)制代碼
19.對(duì)象嵌套屬性解構(gòu)
const?{?info:{?dec}?}?=?{?name:?'張三',?age:?13,?info:{dec:?'描述1',?info:?'信息'?}}
console.log(dec)?//?描述1
復(fù)制代碼
20.解構(gòu)對(duì)象屬性別名
const?{?name:newName?}?=?{?name:?'張三',?age:?13?}
console.log(newName)??//?張三
復(fù)制代碼
21.解構(gòu)對(duì)象屬性默認(rèn)值
const?{?dec='這是默認(rèn)dec值'?}?=?{?name:?'張三',?age:?13?}
console.log(dec)?//這是默認(rèn)dec值
復(fù)制代碼
22.攔截對(duì)象
利用Object.defineProperty攔截對(duì)象
無法攔截?cái)?shù)組的值
let?obj?=?{?name:?'',?age:?'',?sex:?''?},
??defaultName?=?["這是姓名默認(rèn)值1",?"這是年齡默認(rèn)值1",?"這是性別默認(rèn)值1"];
Object.keys(obj).forEach(key?=>?{
??Object.defineProperty(obj,?key,?{?//?攔截整個(gè)object?對(duì)象,并通過get獲取值,set設(shè)置值,vue?2.x的核心就是這個(gè)來監(jiān)聽
????get()?{
??????return?defaultName;
????},
????set(value)?{
??????defaultName?=?value;
????}
??});
});
console.log(obj.name);?//?[?'這是姓名默認(rèn)值1',?'這是年齡默認(rèn)值1',?'這是性別默認(rèn)值1'?]
console.log(obj.age);?//?[?'這是姓名默認(rèn)值1',?'這是年齡默認(rèn)值1',?'這是性別默認(rèn)值1'?]
console.log(obj.sex);?//?[?'這是姓名默認(rèn)值1',?'這是年齡默認(rèn)值1',?'這是性別默認(rèn)值1'?]
obj.name?=?"這是改變值1";
console.log(obj.name);?//?這是改變值1
console.log(obj.age);??//?這是改變值1
console.log(obj.sex);?//?這是改變值1
let?objOne?=?{},?defaultNameOne?=?"這是默認(rèn)值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
復(fù)制代碼
利用proxy攔截對(duì)象
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;
復(fù)制代碼
defineProterty和proxy的對(duì)比:
1.defineProterty是es5的標(biāo)準(zhǔn),proxy是es6的標(biāo)準(zhǔn);
2.proxy可以監(jiān)聽到數(shù)組索引賦值,改變數(shù)組長(zhǎng)度的變化;
3.proxy是監(jiān)聽對(duì)象,不用深層遍歷,defineProterty是監(jiān)聽屬性;
4.利用defineProterty實(shí)現(xiàn)雙向數(shù)據(jù)綁定(vue2.x采用的核心)
23.對(duì)象深度拷貝
JSON.stringify深度克隆對(duì)象;
1.無法對(duì)函數(shù) 、RegExp等特殊對(duì)象的克隆;
2.會(huì)拋棄對(duì)象的constructor,所有的構(gòu)造函數(shù)會(huì)指向Object;
3.對(duì)象有循環(huán)引用,會(huì)報(bào)錯(cuò)
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?????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);
??}
??//?防止循環(huán)引用
??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;
??}
??//?克隆對(duì)象和數(shù)組
??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?]?}
復(fù)制代碼
對(duì)象深度克隆實(shí)際上就是要兼容Array,RegExp,Date,F(xiàn)unction類型;
克隆函數(shù)可以用正則取出函數(shù)體和參數(shù),再定義一個(gè)函數(shù)將取出來的值賦值進(jìn)去
詳細(xì)請(qǐng)戳對(duì)象深度拷貝
24.對(duì)象是否相等
如果用JSON.stringify轉(zhuǎn)化屬性順序不同,也不相等;
而且不支持無法對(duì)函數(shù) 、RegExp等特殊對(duì)象的克隆
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?
????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
復(fù)制代碼
判斷對(duì)象是否相等,實(shí)際上就是要處理Array,Date,RegExp,Object,F(xiàn)unction的特殊類型是否相等
25.對(duì)象轉(zhuǎn)化為字符串
通過字符串+Object 的方式來轉(zhuǎn)化對(duì)象為字符串(實(shí)際上是調(diào)用 .toString() 方法)
'the?Math?object:'?+?Math.ceil(3.4)????????????????//?"the?Math?object:4"
'the?JSON?object:'?+?{name:'曹操'}??????????????//?"the?JSON?object:[object?Object]"
復(fù)制代碼
覆蓋對(duì)象的toString和valueOf方法來自定義對(duì)象的類型轉(zhuǎn)換
2??*?{?valueOf:?()=>'4'?}????????????????//?8
'J'?+?{?toString:?()=>'ava'?}????????????????//?"Java"
復(fù)制代碼
當(dāng)+用在連接字符串時(shí),當(dāng)一個(gè)對(duì)象既有toString方法又有valueOf方法時(shí)候,JS通過盲目使用valueOf方法來解決這種含糊;
對(duì)象通過valueOf方法強(qiáng)制轉(zhuǎn)換為數(shù)字,通過toString方法強(qiáng)制轉(zhuǎn)換為字符串
''?+?{toString:()=>'S',valueOf:()=>'J'}??//J
復(fù)制代碼
Function
26.函數(shù)隱式返回值
(()=>3)()??//3
(()=>(
???3
))()
復(fù)制代碼
函數(shù)省略大括號(hào),或者將大括號(hào)改成小括號(hào)可以確保代碼以單個(gè)語(yǔ)句的形式進(jìn)行求值
27.函數(shù)自執(zhí)行
const?Func?=?function()?{}();?//?常用
(function()?{})();?//?常用
(function()?{}());?//?常用
[function()?{}()];
new?function()?{};
new?function()?{}();
void?function()?{}();
typeof?function()?{}();
delete?function()?{}();
+?function()?{}();
-?function()?{}();
~?function()?{}();
!?function()?{}();
復(fù)制代碼
28.函數(shù)異步執(zhí)行
Promise
Promise.reject('這是第二個(gè)?reject?值').then((data)=>{
??console.log(data)
}).catch(data=>{
??console.log(data)?//這是第二個(gè)?reject?值
})
復(fù)制代碼
Generator
function*?gen(x)?{
??const?y?=?yield?x?+?6;
??return?y;
}
//?yield?如果用在另外一個(gè)表達(dá)式中,要放在()里面
//?像上面如果是在=右邊就不用加()
function*?genOne(x)?{
??const?y?=?`這是第一個(gè)?yield?執(zhí)行:${yield?x?+?1}`;
??return?y;
}
const?g?=?gen(1);
//執(zhí)行?Generator?會(huì)返回一個(gè)Object,而不是像普通函數(shù)返回return?后面的值
g.next()?//?{?value:?7,?done:?false?}
//調(diào)用指針的?next?方法,會(huì)從函數(shù)的頭部或上一次停下來的地方開始執(zhí)行,直到遇到下一個(gè)?yield?表達(dá)式或return語(yǔ)句暫停,也就是執(zhí)行yield?這一行
//?執(zhí)行完成會(huì)返回一個(gè)?Object,
//?value?就是執(zhí)行?yield?后面的值,done?表示函數(shù)是否執(zhí)行完畢
g.next()?//?{?value:?undefined,?done:?true?}
//?因?yàn)樽詈笠恍?return?y?被執(zhí)行完成,所以done?為?true
復(fù)制代碼
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();
復(fù)制代碼
String
29.字符串翻轉(zhuǎn)
function?reverseStr(str?=?"")?{
??return?str.split("").reduceRight((t,?v)?=>?t?+?v);
}
const?str?=?"reduce123";
console.log(reverseStr(str));?//?"321recuder"
復(fù)制代碼
30.url參數(shù)序列化
將對(duì)象序列化成url參數(shù)傳遞
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"
復(fù)制代碼
31.url參數(shù)反序列化
一般會(huì)通過location.search拿到路由傳遞的參數(shù),并進(jìn)行反序列化得到對(duì)象
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"?}
復(fù)制代碼
32.轉(zhuǎn)化為字符串
const?val?=?1?+?"";?//?通過+?''空字符串轉(zhuǎn)化
console.log(val);?//?"1"
console.log(typeof?val);?//?"string"
const?val1?=?String(1);
console.log(val1);?//?"1"
console.log(typeof?val1);?//?"string"
復(fù)制代碼
Number
33.數(shù)字千分位
方法一:
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"
復(fù)制代碼
方法二
console.log('1234567890'.replace(/\B(?=(\d{3})+(?!\d))/g,?","))
console.log((1234567890).toLocaleString())
復(fù)制代碼
34.字符串轉(zhuǎn)數(shù)字
方法一
用*1來轉(zhuǎn)化為數(shù)字,實(shí)際上是調(diào)用.valueOf方法
'32'?*?1????????????//?32
'ds'?*?1????????????//?NaN
null?*?1????????????//?0
undefined?*?1????//?NaN
1??*?{?valueOf:?()=>'3'?}????????//?3
復(fù)制代碼
方法二
+?'123'????????????//?123
+?'ds'???????????????//?NaN
+?''????????????????????//?0
+?null??????????????//?0
+?undefined????//?NaN
+?{?valueOf:?()=>'3'?}????//?3
復(fù)制代碼
35.判斷小數(shù)是否相等
肯定有人會(huì)說這還不簡(jiǎn)單,直接用'==='比較;
實(shí)際上0.1+0.2 !==0.3,因?yàn)橛?jì)算機(jī)不能精確表示0.1, 0.2這樣的浮點(diǎn)數(shù),所以相加就不是0.3了
Number.EPSILON=(function(){???//解決兼容性問題
????return?Number.EPSILON?Number.EPSILON:Math.pow(2,-52);
})();
//上面是一個(gè)自調(diào)用函數(shù),當(dāng)JS文件剛加載到內(nèi)存中,就會(huì)去判斷并返回一個(gè)結(jié)果
function?numbersequal(a,b){?
????return?Math.abs(a-b)??}
//接下來再判斷???
const?a=0.1+0.2,?b=0.3;
console.log(numbersequal(a,b));?//這里就為true了
復(fù)制代碼
36.雙位運(yùn)算符
雙位運(yùn)算符比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
復(fù)制代碼
所以負(fù)數(shù)時(shí),雙位運(yùn)算符和Math.ceil結(jié)果一致,正數(shù)時(shí)和Math.floor結(jié)果一致
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
復(fù)制代碼
判斷奇偶數(shù)
const?num=5;
!!(num?&?1)?//?true
!!(num?%?2)?//?true
復(fù)制代碼
Boolean
38.判斷數(shù)據(jù)類型
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
復(fù)制代碼
可判斷類型:undefined、null、string、number、boolean、array、object、symbol、date、regexp、function、asyncfunction、arguments、set、map、weakset、weakmap
39.使用Boolean過濾數(shù)組假值
const?compact?=?arr?=>?arr.filter(Boolean)
compact([0,?1,?false,?2,?'',?3,?'a',?'e'?*?23,?NaN,?'s',?34])??//[?1,?2,?3,?'a',?'s',?34?]
復(fù)制代碼
40.短路運(yùn)算
||(或)
const?flag?=?false?||?true?//true
//?某個(gè)值為假時(shí)可以給默認(rèn)值
const?arr?=?false?||?[]
復(fù)制代碼
&&(與)
const?flag1?=?false?&&?true?//false
const?flag2?=?true?&&?true?//true
復(fù)制代碼
41.switch 簡(jiǎn)寫
可以用對(duì)象替代switch,提高代碼可讀性
switch(a)?{
??case?'張三':
????return?'age是12'
??case?'李四':
????return?'age是120'
}
//?使用對(duì)象替換后
const?obj?={
??'張三':?'age12',
??'李四':?'age120',
}
console.log(obj['張三'])
復(fù)制代碼
結(jié)語(yǔ)
源碼地址 https://github.com/lanzhsh/react-vue-koa/tree/master/js/skill;
原創(chuàng)碼字不易,歡迎start!

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點(diǎn)擊“閱讀原文”查看70+篇原創(chuàng)文章

