1. 收藏好了,JS開發(fā)須知道的41個小技巧

        共 16633字,需瀏覽 34分鐘

         ·

        2020-11-07 14:48

        來自:掘金,作者:火狼1
        鏈接:https://juejin.im/post/6854573212890562573

        JS是前端的核心,但有些使用技巧你還不一定知道;
        本文梳理了JS的41個技巧,幫助大家提高JS的使用技巧;
        文章有點(diǎn)長,可以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ù)組對象
        數(shù)組對象目前僅針對value值為簡單的Number,String,Boolan數(shù)據(jù)類型 文中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?}]
        復(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ù)組對象
        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相對于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ù)組對象
        //?對象數(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ǔ)集

        兩個數(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ù)組對象
        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相對于arr2所沒有的集合,補(bǔ)集是兩個數(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ù)組對象
        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ù)組對象
        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ù)制代碼
        兩個種類型數(shù)組都可以使用sort排序,sort是瀏覽器內(nèi)置方法;
        默認(rèn)是升序排序,默認(rèn)返回一個函數(shù),有兩個參數(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ù)組對象中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ù)組對象
        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ù)組對象
        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ù)組對象
        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ù)組對象
        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ù)組對象
        const?arr?=?[{?age:?3?},?{?age:?4?},?{?age:?5?}]
        arr.some(item?=>?{?return?item.age?true
        復(fù)制代碼

        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'?]
        復(fù)制代碼
        可見sort排序?qū)φ麛?shù)可以,類似版本號這個格式就不適用了,因?yàn)閟ort函數(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ù)制代碼
        可以看出這個函數(shù)均兼容整數(shù),非整數(shù),字母;
        字母排序是根據(jù)Unicode排序的,所以1.10b在1.10C的后面

        14. 對象轉(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)對象

        將數(shù)組的值轉(zhuǎn)化為對象的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];?//后面一定要加分號,因?yàn)椴患咏忉屍鲿J(rèn)為在讀數(shù)組
        [arr[1],?arr[0]]?=?[arr[0],?arr[1]];?//?[2,1]
        復(fù)制代碼

        Object

        17.對象變量屬性

        const?flag?=?true;
        const?obj?=?{
        ????a:?0,
        ????[flag???"c"?:?"d"]:?2
        };
        //?obj?=>?{?a:?0,?c:?2?}
        復(fù)制代碼

        18.對象多余屬性刪除

        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.對象嵌套屬性解構(gòu)

        const?{?info:{?dec}?}?=?{?name:?'張三',?age:?13,?info:{dec:?'描述1',?info:?'信息'?}}
        console.log(dec)?//?描述1
        復(fù)制代碼

        20.解構(gòu)對象屬性別名

        const?{?name:newName?}?=?{?name:?'張三',?age:?13?}
        console.log(newName)??//?張三
        復(fù)制代碼

        21.解構(gòu)對象屬性默認(rèn)值

        const?{?dec='這是默認(rèn)dec值'?}?=?{?name:?'張三',?age:?13?}
        console.log(dec)?//這是默認(rèn)dec值
        復(fù)制代碼

        22.攔截對象

        利用Object.defineProperty攔截對象
        無法攔截數(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,?{?//?攔截整個object?對象,并通過get獲取值,set設(shè)置值,vue?2.x的核心就是這個來監(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攔截對象
        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的對比:
        1.defineProterty是es5的標(biāo)準(zhǔn),proxy是es6的標(biāo)準(zhǔn);
        2.proxy可以監(jiān)聽到數(shù)組索引賦值,改變數(shù)組長度的變化;
        3.proxy是監(jiān)聽對象,不用深層遍歷,defineProterty是監(jiān)聽屬性;
        4.利用defineProterty實(shí)現(xiàn)雙向數(shù)據(jù)綁定(vue2.x采用的核心)

        23.對象深度拷貝

        JSON.stringify深度克隆對象;
        1.無法對函數(shù) 、RegExp等特殊對象的克隆;
        2.會拋棄對象的constructor,所有的構(gòu)造函數(shù)會指向Object;
        3.對象有循環(huán)引用,會報錯
        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;
        ??}

        ??//?克隆對象和數(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ù)制代碼
        對象深度克隆實(shí)際上就是要兼容Array,RegExp,Date,F(xiàn)unction類型;
        克隆函數(shù)可以用正則取出函數(shù)體和參數(shù),再定義一個函數(shù)將取出來的值賦值進(jìn)去
        詳細(xì)請戳對象深度拷貝

        24.對象是否相等

        如果用JSON.stringify轉(zhuǎn)化屬性順序不同,也不相等;
        而且不支持無法對函數(shù) 、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?????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ù)制代碼
        判斷對象是否相等,實(shí)際上就是要處理Array,Date,RegExp,Object,F(xiàn)unction的特殊類型是否相等

        25.對象轉(zhuǎn)化為字符串

        通過字符串+Object 的方式來轉(zhuǎn)化對象為字符串(實(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ù)制代碼
        覆蓋對象的toString和valueOf方法來自定義對象的類型轉(zhuǎn)換
        2??*?{?valueOf:?()=>'4'?}????????????????//?8
        'J'?+?{?toString:?()=>'ava'?}????????????????//?"Java"
        復(fù)制代碼
        當(dāng)+用在連接字符串時,當(dāng)一個對象既有toString方法又有valueOf方法時候,JS通過盲目使用valueOf方法來解決這種含糊;
        對象通過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ù)省略大括號,或者將大括號改成小括號可以確保代碼以單個語句的形式進(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('這是第二個?reject?值').then((data)=>{
        ??console.log(data)
        }).catch(data=>{
        ??console.log(data)?//這是第二個?reject?值
        })
        復(fù)制代碼
        Generator
        function*?gen(x)?{
        ??const?y?=?yield?x?+?6;
        ??return?y;
        }

        //?yield?如果用在另外一個表達(dá)式中,要放在()里面
        //?像上面如果是在=右邊就不用加()
        function*?genOne(x)?{
        ??const?y?=?`這是第一個?yield?執(zhí)行:${yield?x?+?1}`;
        ??return?y;
        }

        const?g?=?gen(1);
        //執(zhí)行?Generator?會返回一個Object,而不是像普通函數(shù)返回return?后面的值
        g.next()?//?{?value:?7,?done:?false?}
        //調(diào)用指針的?next?方法,會從函數(shù)的頭部或上一次停下來的地方開始執(zhí)行,直到遇到下一個?yield?表達(dá)式或return語句暫停,也就是執(zhí)行yield?這一行
        //?執(zhí)行完成會返回一個?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ù)序列化

        將對象序列化成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ù)反序列化

        一般會通過location.search拿到路由傳遞的參數(shù),并進(jìn)行反序列化得到對象
        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ù)是否相等

        肯定有人會說這還不簡單,直接用'==='比較;
        實(shí)際上0.1+0.2 !==0.3,因?yàn)橛嬎銠C(jī)不能精確表示0.1, 0.2這樣的浮點(diǎn)數(shù),所以相加就不是0.3了
        Number.EPSILON=(function(){???//解決兼容性問題
        ????return?Number.EPSILON?Number.EPSILON:Math.pow(2,-52);
        })();
        //上面是一個自調(diào)用函數(shù),當(dāng)JS文件剛加載到內(nèi)存中,就會去判斷并返回一個結(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ù)時,雙位運(yùn)算符和Math.ceil結(jié)果一致,正數(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
        //?某個值為假時可以給默認(rèn)值
        const?arr?=?false?||?[]
        復(fù)制代碼
        &&(與)
        const?flag1?=?false?&&?true?//false
        const?flag2?=?true?&&?true?//true
        復(fù)制代碼

        41.switch 簡寫

        可以用對象替代switch,提高代碼可讀性
        switch(a)?{
        ??case?'張三':
        ????return?'age是12'
        ??case?'李四':
        ????return?'age是120'
        }

        //?使用對象替換后
        const?obj?={
        ??'張三':?'age12',
        ??'李四':?'age120',
        }
        console.log(obj['張三'])
        復(fù)制代碼

        結(jié)語

        源碼地址 https://github.com/lanzhsh/react-vue-koa/tree/master/js/skill;
        原創(chuàng)碼字不易,歡迎start!

        ??愛心三連擊

        1.看到這里了就點(diǎn)個在看支持下吧,你的點(diǎn)贊,在看是我創(chuàng)作的動力。

        2.關(guān)注公眾號程序員成長指北,回復(fù)「1」加入Node進(jìn)階交流群!「在這里有好多 Node 開發(fā)者,會討論 Node 知識,互相學(xué)習(xí)」!

        3.也可添加微信【ikoala520】,一起成長。


        “在看轉(zhuǎn)發(fā)”是最大的支持

        瀏覽 49
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
          
          

            1. 日日拍夜夜拍 | 欧美日韩1234 | 放荡的少妇2做爰免费观看 | 丝袜脚交一区二区三区 | 台湾三级网 |