Javascript数组研究05_手写实现_map_pop_push_reduce_reduceRight_reverse

20 Array.map()

20.1 基本介绍

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

array.map(callbackFn)
array.map(callbackFn, thisArg)

输入参数

  • callbackFn(element, index, array):生成新数组元素的函数。
  • thisArg(可选):执行 callbackFn 时使用的 this 值。

输出:一个新的数组,每个元素是原数组元素调用 callbackFn 后的返回值。

注意事项

  • map() 不会修改原数组,是一个复制方法
  • 对于稀疏数组,map() 会跳过空槽,不会调用 callbackFn
  • 如果 callbackFn 修改了数组,则修改可能会影响后续的遍历。
20.2 手写实现
MyArray.prototype.map = function(callbackFn, thisArg) {
    if (typeof callbackFn !== 'function') {
        throw new TypeError(callbackFn + ' is not a function');
    }

    let result = new MyArray();

    for (let i = 0; i < this.length; i++) {
        if (!(i in this)) continue; // 跳过空槽
        result[i] = callbackFn.call(thisArg, this[i], i, this);
    }

    result.length = this.length; // 保持长度一致

    return result;
};

// 测试用例
let arr = new MyArray(1, 2, 3);
let mappedArr = arr.map(x => x * 2);
console.log(mappedArr); // [2, 4, 6]

let arr2 = new MyArray().concat([1, ,3]);
let mappedArr2 = arr2.map((x, index) => index);
console.log(mappedArr2); // [0, , 2]

难点总结

  • 处理稀疏数组:跳过空槽,不调用 callbackFn,在结果数组中保留空槽。
  • 返回新数组:需要返回与原数组同类型的新数组。
  • 保持索引一致:结果数组的长度和索引应与原数组保持一致。

21 Array.pop()

21.1 基本介绍

pop() 方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

array.pop()

输入参数:无。

输出:被移除的元素。如果数组为空,则返回 undefined

注意事项

  • pop() 方法会修改原数组,是一个修改方法
  • 当数组为空时,返回 undefined,数组长度仍为 0
21.2 手写实现
MyArray.prototype.pop = function() {
    // 数组为空时直接返回undefined
    if (this.length === 0) {
        return undefined;
    }

    let lastIndex = this.length - 1;
    let lastElement = this[lastIndex];
    // 使用delete关键字删除对象上的属性
    delete this[lastIndex];
    // 记得更新length
    this.length = lastIndex;

    return lastElement;
};

// 测试用例
let arr_3 = new MyArray(1, 2, 3);
let poppedElement = arr_3.pop();
console.log(poppedElement); // 3
console.log(arr_3); // [1, 2]

let emptyArr = new MyArray();
let poppedFromEmpty = emptyArr.pop();
console.log(poppedFromEmpty); // undefined
console.log(emptyArr); // []

难点总结

  • 更新 length 属性:需要手动更新数组的 length 属性。
  • 删除元素:使用 delete 操作符删除最后一个元素,数组的索引:值也可以看作是对象的属性进行删除。
  • 处理空数组:当数组为空时,返回 undefined

22 Array.push()

22.1 基本介绍

push() 方法将一个或多个元素添加到数组的末尾,并返回新数组的长度。

array.push(element1)
array.push(element1, element2, ..., elementN)

输入参数

  • elementN:要添加到数组末尾的元素。

输出:数组添加新元素后的长度。

注意事项

  • push() 方法会修改原数组,是一个修改方法
  • 可以同时添加多个元素。
22.2 手写实现
MyArray.prototype.push = function(...args) {
    let length = this.length >>> 0; // 确保 length 为非负整数\

    // 剩余参数是数组的形式,遍历剩余参数,依次加入原数组
    for (let i = 0; i < args.length; i++) {
        this[length + i] = args[i];
    }
    // 记得更新数组长度
    this.length = length + args.length;

    // 返回数组长度
    return this.length;
};

// 测试用例
let arr_4 = new MyArray(1, 2, 3);
let newLength = arr_4.push(4, 5);
console.log(newLength); // 5
console.log(arr_4); // [1, 2, 3, 4, 5]

难点总结

  • 处理 length 属性:需要正确更新数组的 length 属性。
  • 支持多个参数push() 可以接受多个参数,需要遍历 args

23 Array.reduce()

23.1 基本介绍

reduce() 方法对数组中的每个元素执行一个 reducer 函数(升序执行),将其结果汇总为单个返回值。

array.reduce(callbackFn)
array.reduce(callbackFn, initialValue)

输入参数

  • callbackFn(previousValue, currentValue, currentIndex, array):一个函数,用于执行数组中的每个元素,包含四个参数。
  • initialValue(可选):作为第一次调用 callbackFn 时的第一个参数的值。如果没有提供初始值,则使用数组中的第一个元素。

输出:累加器最终的结果值。

注意事项

  • 如果没有提供 initialValue,且数组为空,会抛出 TypeError
  • 如果没有提供 initialValue,则从索引 1 开始迭代,previousValue 为数组第一个元素。
  • 对于稀疏数组,跳过空槽,但索引会递增。
  • 不像其它方法,reduce方法不接受参数thisArg
23.2 手写实现
MyArray.prototype.reduce = function(callbackFn, initialValue) {
    if (typeof callbackFn !== 'function') {
        throw new TypeError(callbackFn + ' is not a function');
    }

    let length = this.length >>> 0;
    let k = 0;
    let accumulator;

    if (arguments.length > 1) {
        accumulator = initialValue;
    } else {
        // 找到第一个有效值作为初始值
        while (k < length && !(k in this)) {
            k++;
        }
        if (k >= length) {
            throw new TypeError('Reduce of empty array with no initial value');
        }
        accumulator = this[k++];
    }

    for (; k < length; k++) {
        if (k in this) {
            accumulator = callbackFn(accumulator, this[k], k, this);
        }
    }

    return accumulator;
};


// 测试用例
let arr_5 = new MyArray(1, 2, 3, 4);
let sum = arr_5.reduce((prev, curr) => prev + curr);
console.log(sum); // 10

let arr_6 = new MyArray().concat([1, , 3, 4]);
let sum2 = arr_6.reduce((prev, curr) => prev + curr, 0);
console.log(sum2); // 8

难点总结

  • 处理初始值:需要正确处理是否提供了 initialValue
  • 处理稀疏数组:跳过空槽,但索引和循环计数需要正确。
  • 错误处理:当数组为空且未提供 initialValue 时,需要抛出错误。

24 Array.reduceRight()

24.1 基本介绍

reduceRight() 方法对数组中的每个元素执行一个 reducer 函数(从右到左),将其结果汇总为单个返回值。

array.reduceRight(callbackFn)
array.reduceRight(callbackFn, initialValue)

输入参数

  • callbackFn(previousValue, currentValue, currentIndex, array):一个函数,用于执行数组中的每个元素,包含四个参数。
  • initialValue(可选):作为第一次调用 callbackFn 时的第一个参数的值。如果没有提供初始值,则使用数组中的最后一个元素。

输出:累加器最终的结果值。

注意事项

  • 如果没有提供 initialValue,且数组为空,会抛出 TypeError
  • 如果没有提供 initialValue,则从索引 length - 2 开始迭代,previousValue 为数组最后一个元素。
  • 对于稀疏数组,跳过空槽,但索引会递减。
24.2 手写实现
MyArray.prototype.reduceRight = function(callbackFn, initialValue) {
    if (typeof callbackFn !== 'function') {
        throw new TypeError(callbackFn + ' is not a function');
    }

    let length = this.length >>> 0;
    let k = length - 1;
    let accumulator;

    if (arguments.length > 1) {
        accumulator = initialValue;
    } else {
        // 找到最后一个有效值作为初始值
        while (k >= 0 && !(k in this)) {
            k--;
        }
        if (k < 0) {
            throw new TypeError('Reduce of empty array with no initial value');
        }
        accumulator = this[k--];
    }

    for (; k >= 0; k--) {
        if (k in this) {
            accumulator = callbackFn(accumulator, this[k], k, this);
        }
    }

    return accumulator;
};

// 测试用例
let arr_7 = new MyArray(1, 2, 3, 4);
let result = arr_7.reduceRight((prev, curr) => prev - curr);
console.log(result); // -2 ((4 - 3) - 2) - 1

let arr_8 = new MyArray().concat([1, , 3, 4]);
let result2 = arr_8.reduceRight((prev, curr) => prev + curr, 0);
console.log(result2); // 8

难点总结

  • 处理初始值:需要正确处理是否提供了 initialValue
  • 处理稀疏数组:跳过空槽,但索引和循环计数需要正确。
  • 错误处理:当数组为空且未提供 initialValue 时,需要抛出错误。

25 Array.reverse()

25.1 基本介绍

reverse() 方法将数组中元素的位置颠倒,并返回该数组。第一个元素会成为最后一个,最后一个元素会成为第一个。

array.reverse()

输入参数:无。

输出:颠倒顺序后的数组,原数组已被修改。

注意事项

  • reverse() 方法会修改原数组,是一个修改方法
  • 对于稀疏数组,reverse() 会保留空槽的位置。
25.2 手写实现
MyArray.prototype.reverse = function() {
    let length = this.length >>> 0;
    let middle = Math.floor(length / 2);

    for (let i = 0; i < middle; i++) {
        // 判断存在性,为是否删除元素提供依据
        let lowerExists = i in this;
        let upperExists = (length - 1 - i) in this;

        // 根据存在性获取值
        let lowerValue = lowerExists ? this[i] : undefined;
        let upperValue = upperExists ? this[length - 1 - i] : undefined;

        // 进行交换流程
        if (lowerExists) {
            this[length - 1 - i] = lowerValue;
        } else {
            // 如果交换过来的值是空槽,删除对应的属性
            delete this[length - 1 - i];
        }

        if (upperExists) {
            this[i] = upperValue;
        } else {
            delete this[i];
        }
    }

    return this;
};

// 测试用例
let arr_9 = new MyArray(1, 2, 3, 4);
arr_9.reverse();
console.log(arr_9); // [4, 3, 2, 1]

let arr_10 = new MyArray().concat([1, , 3]);
arr_10.reverse();
console.log(arr_10); // [3, , 1]

难点总结

  • 处理稀疏数组:需要正确处理空槽的位置,交换元素时如果元素不存在,那么使用delete操作符删除对应位置上的元素。
  • 原地修改:需要在原数组上进行修改,不能创建新数组,所以需要提前对元素的存在性和值进行判断。
  • 交换元素:需要注意元素的存在性,避免错误覆盖或删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

It'sMyGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值