JS常用方法原生實現(xiàn)

本文目錄:

  • 1.手寫reduce
  • 2.手寫map
  • 3.手寫filter
  • 4.手寫防抖
  • 5.手寫節(jié)流
  • 6.實現(xiàn)flat
  • 7.手寫深拷貝
  • 8.手寫Promise

1.手寫reduce

reduce 接收兩個參數(shù):
第一個參數(shù)是在每一項上調(diào)用的函數(shù)
該函數(shù)接收 4 個參數(shù):
1.前一個值 prev
2.當(dāng)前值 cur
3.項的索引 index
4.數(shù)組對象 array
第二個可選參數(shù)是作為歸并基礎(chǔ)的初始值
reduce 方法返回一個最終的值

Array.prototype.myReduce = function (fn, initialValue) {
  console.log(this)
  let acc = initialValue || this[0];
  const startIndex = initialValue ? 0 : 1;
  for (let i = startIndex; i < this.length; i++) {
    acc = fn(acc, this[i], i, this);
  }
  return acc;
};

2.手寫map

map 迭代方法接收兩個參數(shù):

  • 對每一項執(zhí)行的函數(shù)
    • 該函數(shù)接收三個參數(shù):
      • 數(shù)組項的值
      • 數(shù)組項的下標(biāo)
      • 數(shù)組對象本身
  • 指定 this 的作用域?qū)ο?/li>

map 方法返回每次函數(shù)調(diào)用結(jié)果組成的數(shù)組。
代碼表示:

arr.map(function(item, index, arr) {}, this);

代碼實現(xiàn):

Array.prototype.myMap = function (fn, context) {
  const array = this
  context = Object(context) || global   // 嚴(yán)格模式下
  const resultArr = []
  
  for (let i = 0; i < array.length; i++) {
    let item = array[i]
    result = fn.call(context, item, i, array)
    resultArr.push(result)
  }
  return resultArr
};

注: 嚴(yán)格模式下,context 為 null 或 undefined 時 Object(context) 返回空對象,不會被賦值為global

3.手寫filter

filter 方法接收兩個參數(shù):

  • 對每一項執(zhí)行的函數(shù)
    • 該函數(shù)接收三個參數(shù):
      • 數(shù)組項的值
      • 數(shù)組項的下標(biāo)
      • 數(shù)組對象本身
  • 指定 this 的作用域?qū)ο?/li>

filter 方法返回 執(zhí)行結(jié)果為true的項組成的數(shù)組。
代碼表示:

arr.filter(function(item, index, arr){}, context)

代碼實現(xiàn):

Array.prototype.fakeFilter = function fakeFilter(fn, context) {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function`);
  }
  
  let arr = this;
  let temp = [];

  for (let i = 0; i < arr.length; i++) {
    let result = fn.call(context, arr[i], i, arr);
    if (result) temp.push(arr[i]);
  }
  return temp;
};

4.手寫防抖

函數(shù)防抖 是指在事件被觸發(fā) n 秒后再執(zhí)行回調(diào),如果在這 n 秒內(nèi)事件又被觸發(fā),則重新計時。這可以使用在一些點擊請求的事件上,避免因為用戶的多次點擊向后端發(fā)送多次請求。
通俗點講就是=>你點的再快都沒用(新的點擊會清除上一次的點擊效果),要特定時間之后才會觸發(fā)
代碼示例

let time2;
document.getElementById('防抖').onclick =
  function () {
      clearTimeout(time2);
      time2=setTimeout(function () {
      //do something***
      },2000);
  };

5.手寫節(jié)流

函數(shù)節(jié)流 是指規(guī)定一個單位時間,在這個單位時間內(nèi),只能有一次觸發(fā)事件的回調(diào)函數(shù)執(zhí)行,如果在同一個單位時間內(nèi)某事件被觸發(fā)多次,只有一次能生效。節(jié)流可以使用在 scroll 函數(shù)的事件監(jiān)聽上,通過事件節(jié)流來降低事件調(diào)用的頻率。
通俗點講就是=>點擊就可以觸發(fā)事件,但是特定時間內(nèi)只會觸發(fā)一次,(技能冷卻)
代碼示例

let bool=true;
document.getElementById('節(jié)流').onclick = function () {
   if(bool){
     //do something***
     bool=false;
     setTimeout(()=>{
       bool=true
     },2000)
   }
}

6.實現(xiàn)flat

flat() 方法會按照一個可指定的深度遞歸遍歷數(shù)組,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個新數(shù)組返回。
定義一個數(shù)組ary以及將ary轉(zhuǎn)換為字符串str

let ary = [1, [2, [3, [4, 5]]], 6];
let str = JSON.stringify(ary);

直接調(diào)用flat方法實現(xiàn)多維數(shù)組的扁平化

let ary_flat = ary.flat(Infinity);

如果不用flat,第一種實現(xiàn)方法

ary = str.replace(/(\[\]))/g, '').split(',');

第二種實現(xiàn)方法

str = str.replace(/(\[\]))/g, '');
str = '[' + str + ']';
ary = JSON.parse(str);

第三種實現(xiàn)方法

let result = [];
let myFlat = function (ary) {
  for (let i = 0; i < ary.length; i++) {
    let item = ary[i];
    if (Array.isArray(ary[i])) {
      myFlat(item);
    } else {
      result.push(item);
    }
  }
  return result;
};

第四種實現(xiàn)方法

while (ary.some(Array.isArray)) {
  console.log('xxx')
  ary = [].concat(...ary);
}

7.手寫深拷貝

我們在使用深拷貝的時候,一定要弄清楚我們對深拷貝的要求程度:是僅“深”拷貝第一層級的對象屬性或數(shù)組元素,還是遞歸拷貝所有層級的對象屬性和數(shù)組元素
怎么檢驗深拷貝成功
改變?nèi)我庖粋€新對象/數(shù)組中的屬性/元素, 都不改變原對象/數(shù)組
方法一:深拷貝的最簡單直接的方法:
乞丐版: JSON.parse(JSON.stringify(object)),缺點諸多(會忽略undefined、symbol、函數(shù);不能解決循環(huán)引用;不能處理正則、new Date())
方法二:手動寫遞歸
基礎(chǔ)版(面試夠用): 淺拷貝+遞歸 (只考慮了普通的 object和 array兩種數(shù)據(jù)類型)

var array = [
   { number: 1 },
   { number: 2 },
   { number: 3 }
];
function copy (obj) {
        var newobj = obj.constructor === Array ? [] : {};
        if(typeof obj !== 'object'){
            return;
        }
        for(var i in obj){
           newobj[i] = typeof obj[i] === 'object' ?
           copy(obj[i]) : obj[i];
        }
        return newobj
}
var copyArray = copy(array)
copyArray[0].number = 100;
console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

上面這兩個深拷貝的方法最大缺點是都會丟失函數(shù)Function、正則表達(dá)式等特殊類型。

8.手寫Promise

簡單版本,理解其原理

function myPromise(executor) {
  var _this = this;
  this.onFulfilled = []; //成功的回調(diào)
  this.onRejected = []; //失敗的回調(diào)
  this.state = "PENDING"; //狀態(tài)
  this.value = undefined; //成功結(jié)果
  this.reason = undefined; //失敗原因
  function resolve(value) {
    if (_this.state === "PENDING") {
      _this.state = "FULFILLED";
      _this.value = value;
      _this.onFulfilled.forEach((fn) => fn(value));
    }
  }
  function reject(reason) {
    if (_this.state === "PENDING") {
      _this.state = "REJECTED";
      _this.reason = reason;
      _this.onRejected.forEach((fn) => fn(reason));
    }
  }
  try {
    executor(resolve, reject);
  } catch (e) {
    reject(e);
  }
}
// 定義鏈?zhǔn)秸{(diào)用的then方法
myPromise.prototype.then = function (onFullfilled, onRejected) {
  if (this.state === "FULFILLED") {
    typeof onFulfilled === "function" && onFulfilled(this.value);
  }
  if (this.state === "REJECTED") {
    typeof onRejected === "function" && onRejected(this.reason);
  }
  if (this.state === "PENDING") {
    typeof onFulfilled === "function" &&
      this.onFulfilled.push(onFulfilled);
    typeof onRejected === "function" && this.onRejected.push(onRejected);
  }
};
var myP = new myPromise((resolve, reject) => {
  console.log("執(zhí)行");
  setTimeout(() => {
    reject(3);
  }, 1000);
});
myP.then(
  (res) => {
    console.log(res);
  },
  (err) => {
    console.log(err);
  }
);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容