天天看點

前端為什麼有的接口明明是成功回調卻執行了.catch失敗回調_想知道前端面試如何手寫模拟實作嗎?...模拟call、apply、bind實作快速、希爾、歸并排序數組去重Proxy使用get攔截,實作數組讀取負數的索引Promise的實作

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,裡面有許多前端學習資料 大廠面試真題免費擷取,希望能夠對你們有所幫助。

前端為什麼有的接口明明是成功回調卻執行了.catch失敗回調_想知道前端面試如何手寫模拟實作嗎?...模拟call、apply、bind實作快速、希爾、歸并排序數組去重Proxy使用get攔截,實作數組讀取負數的索引Promise的實作
前端為什麼有的接口明明是成功回調卻執行了.catch失敗回調_想知道前端面試如何手寫模拟實作嗎?...模拟call、apply、bind實作快速、希爾、歸并排序數組去重Proxy使用get攔截,實作數組讀取負數的索引Promise的實作