let obj = { name: 'Michael', age: 18, others: { hobbies: ['basketball', 'gambling'], team: 'Bulls', },}// 遞歸拷貝function deepClone(obj) { if (obj instanceof RegExp) return new RegExp(obj); if (obj instanceof Date) return new Date(obj); if (obj === null || typeof obj !== 'object') return obj //如果不是引用類型則直接傳回 let newObj = new obj.constructor(); //如果obj是數組,newObj=[];如果obj是對象,newObj={} for (let key in obj) { if (obj.hasOwnProperty(key)) { //是否是自身的對象 newObj[key] = deepClone(obj[key]) //指派 } } return newObj}const copyObj = deepClone(obj);obj.others.team = 'Lakers';console.log(obj,copyObj)複制代碼
模拟call、apply、bind實作
Function.prototype.myCall = function (context) { var context = context || window // 給 context 添加一個屬性 // getValue.call(a, 'yck', '24') => a.fn = getValue context.fn = this // 将 context 後面的參數取出來 var args = [...arguments].slice(1) // getValue.call(a, 'yck', '24') => a.fn('yck', '24') var result = context.fn(...args) // 删除 fn delete context.fn return result}Function.prototype.myApply = function (context) { var context = context || window context.fn = this var result // 需要判斷是否存儲第二個參數 // 如果存在,就将第二個參數展開 if (arguments[1]) { result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result}Function.prototype.myBind = function (context) { if (typeof this !== 'function') { throw new TypeError('Error') } var _this = this var args = [...arguments].slice(1) // 傳回一個函數 return function F() { // 因為傳回了一個函數,我們可以 new F(),是以需要判斷 if (this instanceof F) { return new _this(...args, ...arguments) } return _this.apply(context, args.concat(...arguments)) }}複制代碼
快速、希爾、歸并排序
// 快速排序function quickSort(arr) { if (arr.length <= 1) { return arr; } var pivotIndex = Math.floor(arr.length / 2); var pivot = arr.splice(pivotIndex, 1)[0]; var left = []; var right = []; for (var i = 0; i < arr.length; i++) { if (arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat([pivot], quickSort(right));};// 希爾排序function shellSort(arr) { for(let gap = Math.floor(arr.length/2); gap > 0; gap = Math.floor(gap/2)) { // 内層循環與插入排序的寫法基本一緻,隻是每次移動的步長變為 gap for(let i = gap; i < arr.length; i++) { let j = i; let temp = arr[j]; for(; j> 0; j -= gap) { if(temp >= arr[j-gap]) { break; } arr[j] = arr[j-gap]; } arr[j] = temp; } } return arr;}// 歸并排序function mergeSort(arr) { var len = arr.length; if(len < 2) { return arr; } var middle = Math.floor(len / 2), left = arr.slice(0, middle), right = arr.slice(middle); return merge(mergeSort(left), mergeSort(right));}function merge(left, right){ var result = []; while (left.length && right.length) { if (left[0] <= right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } while (left.length) result.push(left.shift()); while (right.length) result.push(right.shift()); return result;}複制代碼
數組去重
[...new Set([1,2,3,1,'a',1,'a'])][1,2,3,1,'a',1,'a'].filter(function(ele,index,array){ return index===array.indexOf(ele)})複制代碼
Proxy使用get攔截,實作數組讀取負數的索引
function createArray(...elements) { let handler = { get(target, propKey, receiver) { let index = Number(propKey); if (index < 0) { propKey = String(target.length + index); } return Reflect.get(target, propKey, receiver); } }; let target = []; target.push(...elements); return new Proxy(target, handler);}let arr = createArray('a', 'b', 'c');arr[-1] // c複制代碼
Promise的實作
class Promise{ constructor(executor){ this.state = 'pending'; this.value = undefined; this.reason = undefined; this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; let resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; this.onResolvedCallbacks.forEach(fn=>fn()); } }; let reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; this.onRejectedCallbacks.forEach(fn=>fn()); } }; try{ executor(resolve, reject); } catch (err) { reject(err); } } then(onFulfilled,onRejected) { // 聲明傳回的promise2 let promise2 = new Promise((resolve, reject)=>{ if (this.state === 'fulfilled') { let x = onFulfilled(this.value); // resolvePromise函數,處理自己return的promise和預設的promise2的關系 resolvePromise(promise2, x, resolve, reject); }; if (this.state === 'rejected') { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); }; if (this.state === 'pending') { this.onResolvedCallbacks.push(()=>{ let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); }) this.onRejectedCallbacks.push(()=>{ let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); }) } }); // 傳回promise,完成鍊式 return promise2; }}function resolvePromise(promise2, x, resolve, reject){ // 循環引用報錯 if(x === promise2){ // reject報錯(檢測到promise的連結循環) return reject(new TypeError('Chaining cycle detected for promise')); } // 防止多次調用 let called; // x不是null 且x是對象或者函數 if (x != null && (typeof x === 'object' || typeof x === 'function')) { try { // A+規定,聲明then = x的then方法 let then = x.then; // 如果then是函數,就預設是promise了 if (typeof then === 'function') { // 就讓then執行 第一個參數是this 後面是成功的回調 和 失敗的回調 then.call(x, y => { // 成功和失敗隻能調用一個 if (called) return; called = true; // resolve的結果依舊是promise 那就繼續解析 resolvePromise(promise2, y, resolve, reject); }, err => { // 成功和失敗隻能調用一個 if (called) return; called = true; reject(err);// 失敗了就失敗了 }) } else { resolve(x); // 直接成功即可 } } catch (e) { // 也屬于失敗 if (called) return; called = true; // 取then出錯了那就不要在繼續執行了 reject(e); } } else { resolve(x); }}複制代碼
如果你現在也想學習前端開發技術,在學習前端的過程當中有遇見任何關于學習方法,學習路線,學習效率等方面的問題,你都可以申請加入我的Q群:前114中6649後671,裡面有許多前端學習資料 大廠面試真題免費擷取,希望能夠對你們有所幫助。
