js手写数组api

  • 本文涉及数组的api有
  • slice
  • concat
  • push
  • pop
  • shift
  • unshift
  • reverse
  • copyWithin
  • entries
  • every
  • fill
  • filter
  • find
  • findIndex
  • forEach
  • from
  • includes
  • indexOf
  • isArray
  • join
  • lastIndexOf
  • map
  • reduce
  • reduceRight
  • some
  • sort
  • splice
  • toString
  • valueOf


本文涉及数组的api有

slice

选取数组的一部分,并返回一个新数组

Array.prototype.mySlice = function(start, end = this.length) {
  const arr = this;
  const result = [];

  if (start < 0) {
    for (let i = start + end; i < end; i++) {
      result.push(arr[i]);
    }
  }
  else {
    for (let i = start; i < end; i++) {
      result.push(arr[i]);
    }
  }
  return result;
};
const arr = [1, 2, 3, 4, 5, 6];
let newArr = arr.mySlice(-4);

console.log(arr, newArr); // [1, 2, 3, 4, 5, 6]  [3, 4, 5, 6]
newArr = arr.mySlice(1);
console.log(newArr); // [2, 3, 4, 5, 6]

concat

连接两个或更多的数组,并返回结果

Array.prototype.myConcat = function () {
  const arr = this;

  for (let i = 0; i < arguments.length; i++) {
    for (let j = 0; j < arguments[i].length; j++) {
      arr[this.length] = arguments[i][j];
    }
  }
  return arr;
};
const arr = ['123', '456'];
const arr1 = ['1', '2', '3'];
const arr2 = ['4', '5', '6'];
const res = arr.myConcat(arr1, arr2);

console.log(arr); // ['123', '456', '1', '2', '3', '4', '5', '6']

push

向数组的末尾添加一个或更多元素,并返回新的长度

Array.prototype.myPush = function () {
  for (let i = 0; i < arguments.length; i++) {
    this[this.length] = arguments[i];
  }
  return this.length;
};
const arr = [1, 2, 3];

const res = arr.myPush(4);
console.log(arr, res); // [1, 2, 3, 4] 4

pop

删除数组的最后一个元素并返回删除的元素

Array.prototype.myPop = function () {
  const arr = this;

  if (arr.length === 0) return undefined;
  const ans = arr[this.length - 1];

  this.length = this.length - 1;
  return ans;
};
const arr = [1, 2, 3];
const res = arr.myPop();

console.log(arr, res); // [1, 2] 3

shift

删除并返回数组的第一个元素

Array.prototype.myShift = function () {
  const arr = this;

  if (arr.length === 0) return undefined;
  const ans = arr[0];

  for (let i = 1; i < arr.length; i++) {
    arr[i - 1] = arr[i];
  }
  this.length = this.length - 1;
  return ans;
};
const arr = [1, 2, 3];
const ans = arr.myShift();

console.log(arr, ans); // [2, 3] 1

unshift

向数组的开头添加一个或更多元素,并返回新的长度

Array.prototype.myUnshift = function () {
  const arrLength = this.length;
  const arr = this;

  for (let i = arrLength + arguments.length - 1; i >= 0; i--) {
    if (i > arguments.length - 1) {
      arr[i] = arr[i - arguments.length];
    } 
    else {
      arr[i] = arguments[i];
    }
  }
  return arr.length;
};
const arr = [1, 2, 3];

const res = arr.myUnshift(4);
console.log(arr, res); // [4, 1, 2, 3] 4

reverse

将数组的前后顺序进行调换

Array.prototype.myReverse = function () {
  const arr = this;
  const arrLength = arr.length;
  const copyArr = Array.from(arr);

  for (let i = 0; i < arrLength; i++) {
    arr[arrLength - i - 1] = copyArr[i];
  }
  return arr;
};
const arr = [1, 2, 3];
const ans = arr.myReverse();

console.log(ans); // [3, 2, 1]

copyWithin

从数组的指定位置拷贝元素到数组的另一个指定位置中

Array.prototype.myCopyWithin = function (target, start, end = this.length) {
  const arr = this;

  for (let i = start; i < end; i++) {
    arr[target] = arr[i];
    target++;
  }
  return arr;
};
let arr = ['a', 'b', 'c', 'd', 'e'];

arr.copyWithin(0, 3, 4);
console.log(arr); // ['d', 'b', 'c', 'd', 'e']
arr = ['a', 'b', 'c', 'd', 'e'];
arr.myCopyWithin(0, 3, 4);
console.log(arr); //  ['d', 'b', 'c', 'd', 'e']
arr.myCopyWithin(1, 3);
console.log(arr); //  ['d', 'd', 'e', 'd', 'e']

entries

返回数组的可迭代对象

Array.prototype.myEntries = function () {
  const ans = [];

  for (let i = 0; i < this.length; i++) {
    ans[i] = [];
    ans[i].push(i);
    ans[i].push(this[i]);
  }
  return ans;
};
const arr = ['12313', '12', '545'];

console.log(arr.myEntries());

结果

js文件写axios post_i++

every

检测数值元素的每个元素是否都符合条件

Array.prototype.myEvery = function (fn) {
  const arr = this;
  let count = 0;

  for (let i = 0; i < arr.length; i++) {
    if (fn(arr[i])) {
      count++;
    }
  }
  if (count === arr.length) {
    return true;
  }
  return false;
};

const arr = [1, 2, 3, 4, 5, 6, 7, 8];
let res = arr.myEvery(value => value > 4);

console.log(arr, res); // [1, 2, 3, 4, 5, 6, 7, 8] false
res = arr.myEvery(value => value > 0);
console.log(res); // true

fill

使用一个固定值来填充数组

Array.prototype.myFill = function (value, start = 0, end = this.length) {
  const arr = this;

  for (let i = start; i < end; i++) {
    arr[i] = value;
  }
  return arr;
};
const arr = [1, 2, 3, 4];

arr.myFill(0, 2, 4);
console.log(arr); // [1, 2, 0, 0]
arr.myFill(5, 1);
console.log(arr); // [1, 5, 5, 5]
arr.myFill(6);
console.log(arr); // [6, 6, 6, 6]

filter

检测数值元素,并返回符合条件所有元素的数组

Array.prototype.myFilter = function (fn) {
  if (Object.prototype.toString.call(fn).slice(8, -1) !== 'Function') {
    throw new error('ths first argument must be Function!');
  }
  const arr = this;
  const res = [];

  for (let i = 0; i < arr.length; i++) {
    if (fn(arr[i], i, arr)) {
      res.push(arr[i]);
    }
  }
  return res;
};
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const res = arr.myFilter((value, index, arr) => value > 4);

console.log(arr, res); // [1, 2, 3, 4, 5, 6, 7, 8, 9]  [5, 6, 7, 8, 9]

find

返回符合传入测试(函数)条件的第一个数组元素

Array.prototype.myFind = function (fn) {
  if (typeof fn !== 'function') {
    return new Error(`${fn} is no a function`);
  }
  const self = this;

  for (let i = 0; i < self.length; i++) {
    if (fn(self[i], i, self)) {
      // 如果当前元素满足,则返回此元素
      return self[i];
    }
  }
};
const arr = [1, 2, 5, 4, 5, 6, 7, 8, 9];
const res = arr.myFind((value, index, arr) => value > 4);

console.log(arr, res); // [1, 2, 5, 4, 5, 6, 7, 8, 9] 5

findIndex

返回符合传入测试(函数)条件的数组元素索引

Array.prototype.myFindIndex = function (fn) { 
  if (typeof fn !== 'function') {
    throw TypeError('err function');
  }
  for (let i = 0; i < this.length; i++) {
    if (fn(this[i])) {
      return i;
    }
  }
  return undefined; 
};
const arrFindIndex = [12, 15, 19];
const findIndex = arrFindIndex.myFindIndex(item =>
  item > 12);

console.log('findIndex:' + findIndex); // findIndex:1

forEach

数组每个元素都执行一次回调函数

Array.prototype.myForEach = function (fn, thisArg) {
  const arr = this;

  for (let i = 0; i < arr.length; i++) {
    fn.call(thisArg, arr[i]);
  }
};

const obj = {
  num: 10
};
const arr = [1, 2, 3, 4, 5, 6];

arr.myForEach(function (value, index, arr) {
  console.log(value + this.num); // 依次打印:11 12 13 14 15 16
}, obj);
console.log(arr); // [1, 2, 3, 4, 5, 6]

from

通过给定的对象中创建一个数组

Array.prototype.myFrom = function (object, mapFunction, thisValue) {
  const obj = thisValue || this;
  let result = [];

  // 没有length属性 或者 length 为0的 直接返回空数组
  if (!object.length) {
    return result;
  }
  if (typeof object === 'string') {
    result = object.split('');
  } 
  else {
    object.forEach(item => result.push(item));
  }
  if (typeof mapFunction !== 'function') {
    throw new TypeError(mapFunction + ' is not a function');
  }
  return result.map(mapFunction, thisValue);
};

const r1 = Array.prototype.myFrom([1, 2, 3], x => x * 10);

console.log(r1); // [10, 20, 30, 40]
const r2 = Array.prototype.myFrom('1234', x => x * 10);

console.log(r2); // [10, 20, 30]

includes

判断一个数组是否包含一个指定的值

Array.prototype.myIncludes = function (searchElement, fromIndex = 0) {
  const arr = this;

  if (fromIndex >= arr.length || !arr.length) {
    return false;
  }
  for (let i = fromIndex; i < arr.length; i++) {
    if (arr[i] === searchElement) {
      return true;
    }
  }
  return false;
};

const arr = ['a', 'b', 'c', 'd'];

const result = arr.myIncludes('b');

console.log(result); // true

indexOf

搜索数组中的元素,并返回它所在的位置

Array.prototype.myIndexOf = function (num) {
  const arr = this;

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === num) {
      return i;
    }
  }
  return -1;
};
const arr = [1, 2, 3, 4, 5, 6];

console.log(arr.myIndexOf(5)); // 4

isArray

判断对象是否为数组

Array.prototype.myIsArray = function (item) {
    /*
     * 这里使用Object.prototype.toString.call来判断是否为数组
     * 不能使用typeof来判断,因为不准确,而Object.prototype.toString.call判断类型的方法是最准确的
     */
  return Object.prototype.toString.call(item) === '[object Array]';
};
const arr = [1, 2, 3, 4];

console.log(Array.prototype.myIsArray(arr));  // true

join

把数组的所有元素以某个中间值连接并放入一个字符串

Array.prototype.myJoin = function (separator = ',') {
  const arr = this;
  let str = '';

  for (let i = 0; i < arr.length; i++) {
    str += arr[i];
    if (i != arr.length - 1) {
      str += separator;
    }
  }
  return str;
};

const arr = [1, 2, 3, 4, 5, 6];
const res = arr.myJoin('-');

console.log(arr, res); // [1, 2, 3, 4, 5, 6] '1-2-3-4-5-6'

lastIndexOf

搜索数组中的元素,并返回它最后出现的位置

Array.prototype.myLastIndexOf = function (num) {
  const arr = this;

  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i] === num) return i;
  }
  return -1;
};

const arr = [1, 2, 3, 4, 4, 4];

console.log(arr.myLastIndexOf(4)); // 5

map

通过指定函数处理数组的每个元素,并返回处理后的数组

Array.prototype.myMap = function (fn, thisArg) {
  if (Object.prototype.toString.call(fn).slice(8, -1) !== 'Function') {
    throw new error('The first argument must be a function!');
  }
  const result = [];
  const currentArr = this;

  for (let i = 0; i < currentArr.length; i++) {
    result[i] = fn.call(thisArg, currentArr[i], i, currentArr);
  }
  return result;
};

arr = [1, 2, 3, 4, 5, 6];
console.log(arr.map((item, index, arr) => item * 2)); // [2, 4, 6, 8, 10, 12]
console.log(arr.myMap((item, index, arr) => item + 1)); // [2, 3, 4, 5, 6, 7]

reduce

将数组元素计算为一个值(从左到右)

const arrReduce = [12, 15, 19];
Array.prototype.myReduce = function (fn, obj) {
  if (typeof fn !== 'function') {
    throw new TypeError(`error ${fn} no a function `);
  }
  for (let i = 0; i < this.length; i++) {
    obj = fn(obj, this[i]);
  }
  return obj;
};

const reduce = arrReduce.myReduce((pre, item) => {
  pre = pre + item;
  return pre;
}, 0);

console.log('reduce:' + reduce); // reduce:46

reduceRight

将数组元素计算为一个值(从右到左)

const arrReduce = [12, 15, 19];
Array.prototype.myReduceRight = function (fn, obj) {
  if (typeof fn !== 'function') {
    throw new TypeError(`error ${fn} no a function `);
  }
  for (let i = this.length - 1; i >= 0; i--) {
    obj = fn(obj, this[i]);
  }
  return obj;
};

const reduce = arrReduce.myReduceRight((pre, item) => {
  pre = pre + item;
  return pre;
}, 0);

console.log('reduce:' + reduce); // reduce:46

some

检测数组元素中是否有元素符合指定条件

Array.prototype.mySome = function (fn) { 
  if (typeof fn !== 'function') {
    throw new TypeError(`error ${fn} no a function `);
  }
  for (let i = 0; i < this.length; i++) {
    if (fn(this[i])) {
      return true;
    }
  }
  return false;
};
const arrSome = [12, 15, 19];
const some = arrSome.mySome(item => item > 19);

console.log('some:' + some); // some:false

sort

对数组的元素进行排序(此api可涉及多种排序算法,感兴趣可以去了解,此处使用冒泡排序)

Array.prototype.mySort = function () {
  let arr = this;
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
  return arr;
};
const arrSort = [1, 5, 65, 78, 44, 0, 2, 3, 1, 0, 44, 12, 15, 19];
console.log(arrSort.mySort()); // [0, 0, 1, 1, 2, 3, 5, 12, 15, 19, 44, 44, 65, 78]

splice

从数组中添加或删除元素

Array.prototype.mySplice = function (index, howmany = 0) {
  const arr = this;
  const left = arr.slice(0, index); // 截取左边的数组
  const right = arr.slice(index + howmany, arr.length); // 截取右边的数组
  const subArr = Array.prototype.slice.call(arguments, 2); // 截取参数里面需要添加的数组
  let result = [];

  // 合并数组
  result = [...left, ...subArr, ...right];
  // 这里改变 this, 就是改变原数组
  for (let i = 0; i < result.length; i++) {
    this[i] = result[i];
  }
  // 返回删除的数据
  return this.slice(index, index + howmany);
};
const arr = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
const result = arr.mySplice(2, 1, 'sss', 'xxx');

console.log(result); // ["sss"]
console.log(arr); // ["Banana", "Orange", "sss", "xxx", "Apple", "Mango"]

toString

把数组转换为字符串,并返回结果

Array.prototype.myToString = function (separator = ',') {
  const arr = this;
  let str = '';

  for (let i = 0; i < arr.length; i++) {
    str += arr[i];
    if (i != arr.length - 1) {
      str += separator;
    }
  }
  return str;
};
const arr = [1, 2, 3, 4, 5, 6];
const arr1 = [1, 2, 'a', 'b'];

res = arr1.myToString();
console.log(arr1, res); // [1, 2, 'a', 'b'] '1,2,a,b'

valueOf

返回数组对象的原始值

Array.prototype.myValueOf = function () {
  return this;
};
const arr = [1, 2, 3, 4, 5];

console.log(arr.myValueOf()); // [1, 2, 3, 4, 5]