<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【JS】699- JS開發(fā)必須知道的41個(gè)技巧

          共 16714字,需瀏覽 34分鐘

           ·

          2020-08-29 18:14


          ?作者:火狼
          https://cloud.tencent.com/developer/article/1666138

          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?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?????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!




          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4.?正則 / 框架 / 算法等 重溫系列(16篇全)
          5.?Webpack4 入門(上)||?Webpack4 入門(下)
          6.?MobX 入門(上)?||??MobX 入門(下)
          7.?70+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看70+篇原創(chuàng)文章

          點(diǎn)這,與大家一起分享本文吧~
          瀏覽 85
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲一级a人与一级A片 | 91在线对白 | 黄色三级片视频 | 日本A片黄色 | 91免费成人在线 |