【手写】Array.prototype.map方法

251 阅读2分钟

手写系列文章☞Array.prototype.map

原生的Array.prototype.map

手写实现算法,先掌握原生方法的使用是很重要的。

map() 方法创建一个新数组,其结果是传入数组中的每个元素按顺序调用一次提供的函数后的返回值。具体语法为:

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
       // Return element for new_array 
   }[, thisArg])

在理解这个传参时,对于callback中的参数没有异议,还有一个可选的thisArg参数,之前都没怎么注意map还可以传这个。根据MDN的说法,如果 thisArg 参数提供给map,则会被用作回调函数的this值。map 的第二个参数为第一个参数回调中的this指向,如果第一个参数为箭头函数,那设置第二个this会因为箭头函数的词法绑定而失效。

即如下所示:

// 使用普通函数
const data = [2,3,4,6];
data.map(function(value, index, arr) {
    console.log(this) // [1,2,3]
}, [1,2,3]);

// 使用箭头函数
const data = [2,3,4,6];
data.map((value, index, arr) => {
    console.log(this) // 绑定失效
}, data);

此外,在MDN的说明中,有一行需要特别注意下:

callback函数只会在有值的索引上被调用;那些从来没被赋过值或者使用delete删除的索引则不会被调用。

这个即是在拜读大神们的文章时,提到的稀疏数组

稀疏数组

定义: 稀疏数组是指索引不连续,数组长度大于元素个数的数组,通俗地说就是有空隙的数组。

生成稀疏数组的方式:

// 构造函数声明一个没有元素的数组
    var a = new Array(5);    // [empty × 5]
    a.hasOwnProperty(1); // false

    // 指定的索引值大于数组长度
    var a = [];
    a[5] = 4;                // [empty × 5, 4]

    // 指定大于元素个数的数组长度
    var a = [];
    a.length = 5;            // [empty × 5]

    // 数组直接量中省略值
    var a = [0,,,,];         // [0, empty × 3]

    // 删除数组元素
    var a = [0, 1, 2, 3, 4];
    delete a[4];             // [0, 1, 2, 3, empty]

理解了原生方法的含义和使用方式后,就可以开始手写实现该方法了。

使用循环实现map方法
const myMap = function(fn, context) {
    let arr = Array.prototype.slice.call(this);
    let mappedArr = new Array(arr.length);
    for (let i = 0; i < arr.length; i++) {
        // 判断稀疏数组的情况
        if (!arr.hasOwnProperty(i)) continue;
        mappedArr[i] = fn.call(context, arr[i], i, this);
    }

    return mappedArr;
}

Array.prototype.myMap = myMap;

console.log([4,5,,6].myMap(number => number * 2))
使用reduce实现map方法
const myReduceMap = function(callback, context) {
    const arr = Array.prototype.slice.call(this);
    return arr.reduce((prev, cur, index ,arr) => {
        return [...prev, callback.call(context, cur, index, this)]
    }, [])
}

Array.prototype.myReduceMap = myReduceMap;
console.log([6,7,8].myReduceMap(num => num * 2))

.map方法的使用较为简单,需要注意的就是稀疏数组的处理,还有一个thisArg参数的定义。