手写JavaScript中的数组方法(上)

前言

为了巩固提高javascript的水平,我决定手写一些JavaScript中常见的方法,来达到我们熟悉js的目的。

手写深拷贝 ⛹⛹

我们知道,深拷贝其实就是在堆栈中新开辟一个空间,来克隆一个一摸一样的对象。

我们一般实现深拷贝会使用一下方法:

JSON.stringify(JSON.parse(obj))

通过这种方式我们会开辟一个空间,创建一个和obj一摸一样的对象。

那么我们如何手写一个深拷配的方法呢?

// 手写深拷贝
function deepClone(origin, target) {
  // 首先创建一个变量默认为传入的target对象或者为空对象
  var tar = target || {};
  var toStr = Object.prototype.toString;
  var arrayType = "[object Array]";
  for (const k in origin) {
    //   判断origin带有的属性k是继承来的还是创建的
    if (origin.hasOwnProperty(k)) {
      // 判断当前属性是对象和数组之一吗
      if (typeof origin[k] == "object" &&  origin[k] != null) {
        //  具体判断该属性是数组还是对象
        tar[k] = toStr.call(origin[k]) == arrayType ? [] : {};
        // 进行递归调用,将里面嵌套的对象或者数组也进行拷贝
        deepClone(origin[k], tar[k]);
      } else {
        tar[k] = origin[k];
      }
    }
  }
​
  return tar;
}

我来给大家讲解一些我的实现思路:

  1. 首先这个函数传入两个参数,一个要被克隆的原始对象(origin),一个克隆之后的对象(target)
  2. 然后在这个函数中创建变量tar保存target,或者创建一个空对象
  3. 接着使用for in 方法对传入的origin对象进行遍历,首先判断origin上的属性k是继承来的还是自己创建的。
  4. 然后就对传入的对象的属性进行判断,首先使用type of进行简单的一个过滤判断(因为typeof只能粗略的判断一下基本本数据类型,不能更细致的区分),这里还要注意一下因为null类型也会配判断为object类型,所以我们还要排除一下null类型。
  5. 然后我们就要区分是对象还是数组了,在这里就需要考察对JavaScript的掌握程度了,我们知道因为基本类型中的object类型下面又可以细分为function,array,object,null等类型,要想具体的将他们给区分开就需要使用Object.prototype.toString中的call方法。

Object.prototype.toString.call(null); // “[object Null]” Object.prototype.toString.call(undefined); // “[object Undefined]” Object.prototype.toString.call(“abc”);// “[object String]” Object.prototype.toString.call(123);// “[object Number]” Object.prototype.toString.call(true);// “[object Boolean]”

这个可以清楚的分清楚所属的类型

  1. 所以我们可以通过这行代码来实现针对属性创建一个对象或者数组

tar[k] = toStr.call(origin[k]) == arrayType ? [] : {};

  1. 然后通过递归调用传入origin[k],tar[k],因为此时我们已经可以判断出来origin[k]是对象还是数组了,所以我们传入originp[k]就相当于是最初传入origin一样,传入tar[k],就像是传入target一样。
  2. 然后我们就要给递归一个出口:如果origin中的这个属性不是对象或者数组,那么我们就可以直接进行赋值操作,将origin[k]赋值给tar[k]。
  3. 最后我们将tar给return出去就可以,这样就实现了深拷贝。

手写forEach🛰🛰

废话不多说,先上源代码:

// 手写ForEach方法
Array.prototype.myForEach = function (cb) {
  //   这里的this指的是调用这个方法的数组
  var _arr = this;
  var len = _arr.length;
  //   这个obj2代表的是myForEach的第二个参数,这个参数可以改变this指向
  var arr2 = arguments[1] || window;
  //   根据数组的长度来决定cb这个函数执行的次数
  for (var i = 0; i < len; i++) {
    // apply可以更改this的指向
    cb.apply(arr2, [_arr[i], i, _arr]);
  }
};

思路:

首先我们要给Array.prototype绑定一个myForeEach方法,这个函数接收一个参数是一个回调函数, 然后我们在函数内部声明一个变量用来保存this,首先我们要在这里明白的是这里的this指向调用他的数组,然后这个arr2保存的是可能会传递的二个参数,这个参数可以更改this的指向。然后我们就可以实现遍历,其实本质就是一个for循环,然后根据数组的长度来调用回调函数。其中apply方法可以更改this的指向,然后第二个参数传递一个数组,里面的参数就是要传入回调函数的参数。

实例数据:

let arr = [
  {
    name: "张三",
    age: 21,
  },
  {
    name: "李四",
    age: 24,
  },
  {
    name: "王五",
    age: 31,
  },
];

实际使用

arr.myForEach(function (item, index, arr) {
  // console.log(this);
   console.log(item);
});

手写JavaScript中的数组方法(上)

手写map方法 🐤🐤

先上源代码:

// 手写map方法
Array.prototype.myMap = function (cb) {
  var _arr = this;
  var len = _arr.length;
  var arr2 = arguments[1] || window;
  var newArr = [];
  for (var i = 0; i < len; i++) {
    // 因为map要返回一个新的数组,所以里面如果有对象这种引用类型,需要进行深拷贝
    var _item = deepClone(_arr[i]);
    //  cb调用apply方法需要在cb中进行return,这也是map方法所需要做的
    newArr.push(cb.apply(arr2, [_item, i, _arr]));
  }
  return newArr;
};

注意这个方法前三行代码和forEach是相同的不再赘述,我们主要说不同的地方,首先我们还是使用for循环但是注意这里我们使用了前面写好的深拷贝函数deepClone克隆数组中的元素,然后创建一个新的空数组,将回调函数中return的元素push到newArr中,最后再将newArr给return出去,这样就完成了myMap方法

实际使用:

let newArr = arr.myMap(function (item, index, arr) {
   item.age += 100;
   return item;
 });
console.log(newArr);

这里的arr和示例数据相同,我们可以查看一下返回值:

手写JavaScript中的数组方法(上)

手写filter方法 🥇🥇

我们知道过滤在我们实习的很多项目中都会使用到,可以用来筛选有用的数据,所以我们这次就手写一个

废话不多说,先上代码:

// 手写filter方法
Array.prototype.myFilter = function (cb) {
  var _arr = this;
  var len = _arr.length;
  var arr2 = arguments[1] || window;
  var newArr = [];
  var _item;
  for (var i = 0; i < len; i++) {
    _item = deepClone(_arr[i]);
    cb.apply(arr2, [_item, i, _arr]) ? newArr.push(_item) : "";
  }
  return newArr;
};

思路:

这个代码实现上面其实和之前map的实现方式有一点像,但略有不同,首先相同的是我们要对数组中的元素进行深拷贝,因为涉及对象这个引用类型,为了防止修改原对象就进行深拷贝,我们知道filter方法返回值其实是符合条件的值,所以可以进行判断如果这个值满足要求,那就将他push到newArr中。

实际使用:

let newArr2 = arr.myFilter(function (item, index, arr) {
  return item.age > 25;
});
 console.log(newArr2);

手写JavaScript中的数组方法(上)

总结 🎃🎃

以上就是暂时手写出来的数组方法,后续还会继续更新手写数组方法的内容,通过手写方法可以是我们更加熟悉JavaScript的语法,提升js的基础

原文链接:https://juejin.cn/post/7234058546572607548 作者:前端随想

(0)
上一篇 2023年5月18日 上午10:31
下一篇 2023年5月18日 上午10:41

相关推荐

发表回复

登录后才能评论