#JavaScript編碼能力
##1.多種方式實作數組去重、扁平化、對比優缺點
參考資料:
https://blog.csdn.net/xiaobing_hope/article/details/79458288
https://blog.csdn.net/ganyingxie123456/article/details/77947704
###簡單數組去重
var arr = [1, 43, 4, 3, 2, 4, 3];
// 去重後
arr = [1, 43, 4, 3, 2]
// 傳統方法,for循環實作
function dedupe(arr) {
var rets = [];
for (var i = 0; i < arr.length; i ++) {
if (!rets.includes(arr[i])) {
rets.push(arr[i]);
}
}
return rets;
}
// 方法二: forEach方法實作
function dedupe(arr) {
var rets = [];
arr && arr.forEach(function(item){
if (!rets.includes(item)){
rets.push(item);
}
});
return rets;
}
// ES6方法實作
// es6提供的新的資料結構Set,類似數組,但是成員的值都是唯一的,沒有重複的值。
function dedupe(arr) {
var newSet = new Set(arr); // arr變成了set的資料結構,并去除了其中重複的元素
return Array.from(newSet); // Array.from方法将set資料結構轉為數組資料結構
}
###複雜資料結構的數組去重
// [1,2,{a:1},3,2,{a:1},[1,2],[1,2]]
// 數組中的元素包含對象和數組
function unique(arr) {
const hash = {};
const res = [];
for (let i = 0; i < arr.length; i++) {
if (hash[arr[i]] == null) {
res.push(arr[i]);
hash[arr[i]] = true;
}
}
return res;
}
unique([1,2,{a:1},3,2,{a:1},[1,2],[1,2]]);
// 1, 2, {a: 1}, 3, [1, 2]
###數組去扁平化
數組的扁平化,就是将一個嵌套多層的數組array(嵌套可以是任何層數)轉換為隻有一層的數組
var arr = [1, 2, 3, [4, 3, [2, 7], 2], 5, [5, 9, 10], 7];
// 去扁平化後
arr = [1, 2, 3, 4, 3, 2, 7, 2, 5, 5, 9, 10, 7];
(1)循環遞歸實作
// for循環,如果子元素還是數組,則遞歸調用該方法
function flatten(arr) {
var rets = [];
for(var i = 0; i < arr.length; i ++) {
if (Array.isArray(arr[i])) {
rets = rets.concat(flatten(arr[i]));
} else {
rets.push(arr[i]);
}
}
return rets;
}
// 使用forEach
function flatten(arr) {
var rets = [];
arr && arr.forEach(function(item) => {
if (Array.isArray(item)) {
rets = rets.concat(flatten(item));
} else {
rets.push(item);
}
});
return rets;
}
(2)使用reduce簡化代碼
function flatten(arr) {
return arr.reduce(function(pre, item){
return pre.concat(Array.isArray(item) ? flatten(item) : item);
}, [])
}
(3)如果數組元素都為數字,則可以使用toString方法
function flatten(arr) {
var newArr = arr.toString().split(',');
return newArr.map(function(item){
return +item; // 将字元串轉為數字
});
}
es6提供的新方法 flat(depth)
let a = [1,[2,3]];
a.flat(); // [1,2,3]
a.flat(1); //[1,2,3]
優缺點無非是速度問題,暫時忽略
##2.多種方式實作深拷貝、對比優缺點
參考資料:https://www.cnblogs.com/echolun/p/7889848.html
###1.我們怎麼去實作深拷貝呢,這裡可以遞歸遞歸去複制所有層級屬性。
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判斷ojb子元素是否為對象,如果是,遞歸複制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,簡單複制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
###2.除了遞歸,我們還可以借用JSON對象的parse和stringify
function deepClone(obj){
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
let a=[0,1,[2,3],4],
b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
###3.除了上面兩種方法之外,我們還可以借用JQ的extend方法。
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷貝,為true為深拷貝,為false,則為淺拷貝
target Object類型 目标對象,其他對象的成員屬性将被附加到該對象上。
object1 objectN可選。 Object類型 第一個以及第N個被合并的對象。
let a=[0,1,[2,3],4],
b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
##3.手寫函數柯裡化工具函數、并了解其應用場景和優勢
參考資料:
https://blog.csdn.net/u011500781/article/details/80004517
https://www.cnblogs.com/guolao/p/10144086.html
##4.手寫防抖和節流工具函數、并了解其内部原理和應用場景
參考資料:https://www.cnblogs.com/eggplants/p/9592563.html
在實際開發應用中,經常會碰到高頻率的事件處理,比如 window 的 scroll, resize 以及 keyup,mousemove 等事件。
這些高頻率的事件觸發會帶來一些顯著的問題。 如果事件處理函數調用的頻率無限制,會加重浏覽器的負擔,導緻使用者體驗非常糟糕。
高頻率的事件處理函數中,存在着大量的DOM操作,當浏覽器的渲染速度跟不上事件觸發頻率,容易造成頁面卡頓,影響使用者體驗,甚至會造成 CPU 使用率過高導緻頁面崩潰。
高頻率的事件處理函數中,每執行一次事件處理函數時,都需要和伺服器通信建立 HTTP 請求,比如頁面的搜尋功能,那麼可能存在短時間内發起了數十條 HTTP 請求的情況,容易消耗伺服器資源。
針對這些問題的解決方案,可以采用函數防抖(debounce)和節流(throttle)的方案解決存在的問題,通過防抖和節流可以将多個事件的觸發合并成一個,減少事件觸發頻率。 同時又不影響實際效果。
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null)
clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 處理函數
function handle() {
console.log(Math.random());
}
// 滾動事件
window.addEventListener('scroll', debounce(handle, 1000));
##5.實作一個sleep函數
參考資料:https://www.cnblogs.com/mengfangui/p/9765243.html
//方法一
function sleep1(ms, callback) {
setTimeout(callback, ms)
}
//sleep 1s
sleep1(1000, () => {
console.log(1000)
})
//方法二
function sleep2(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms)
})
}
sleep2(1000).then(() => {
console.log(2000)
})
//方法三
function sleep3(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms)
})
}
async function init() {
await sleep3(1000);
}
init().then(() => {
console.log(3000)
})