美文网首页
JavaScript 回顾(一)map() 与 forEach(

JavaScript 回顾(一)map() 与 forEach(

作者: MercuryWang | 来源:发表于2019-05-12 23:12 被阅读0次

    1. 关于 map() 与 forEach() 的区别

    参考文章援引自 FCC The Differences Between forEach() and map() that Every Developer Should Know

    探讨两者区别主要从以下几点展开:

    • Definitions 定义
    • The returning value 返回值
    • Ability to chain other methods 链式操作其他方法
    • Mutability 是否改变原数组
    • Performance Speed 执行效率
    • Final Thoughts 应用场景的思考
    1.1 Definitions 定义
    • map() 方法的参数是一个函数,然后针对数组的每一个成员执行该函数,最后返回一个全新的数组,该数组由调用函数执行后的结果所填充。也就意味着,新数组的成员是原数组的新形象,新数组的长度与原数组相同。
    const myAwesomeArray = [5, 4, 3, 2, 1]
    
    myAwesomeArray.map(x => x * x)
    
    // Output: [25, 16, 9, 4, 1]
    
    • forEach() 同样接收一个函数作为参数,且对每一个数组成员执行该函数。不过,它并不像 map() 那样会返回一个新数组,它的返回值是 undefined
    const myAwesomeArray = [
      { id: 1, name: "john" },
      { id: 2, name: "Ali" },
      { id: 3, name: "Mass" },
    ]
    
    myAwesomeArray.forEach(element => console.log(element.name))
    // >>>>>>>>> Output : john
    //                    Ali
    //                    Mass
    
    1.2 The returning value 返回值

    返回值上面的定义已经提及了,map() 是返回一个新数组,forEach() 返回 undefined

    const myAwesomeArray = [1, 2, 3, 4, 5]
    myAwesomeArray.forEach(x => x * x)
    //>>>>>>>>>>>>>return value: undefined
    
    myAwesomeArray.map(x => x * x)
    //>>>>>>>>>>>>>return value: [1, 4, 9, 16, 25]
    
    1.3 Ability to chain other methods 链式操作其他方法

    是否可以链式操作是基于返回值的,所以 map() 可以链式调用其他方法,forEach() 不可以。

    const myAwesomeArray = [1, 2, 3, 4, 5]
    myAwesomeArray.forEach(x => x * x).reduce((total, value) => total + value)
    //>>>>>>>>>>>>> Uncaught TypeError: Cannot read property 'reduce' of undefined
    myAwesomeArray.map(x => x * x).reduce((total, value) => total + value)
    //>>>>>>>>>>>>> return value: 55
    
    1.4 Mutability 是否改变原数组

    这个才是重点,改变还是不改变原数组。

    mutable object 可变对象的定义:该对象创建后其状态可以改变即为可变对象。

    根据 MDN 文档的解释:

    • forEach() 不会改变数组对象(但回调函数会改变数组)
    • map() 不会改变数组对象(尽管如此,回调函数如果有援引,可能会改变原数组)

    感觉等于没说,难道是没有区别吗???
    不,当然有。区别就在于 map() 方法返回一个全新的数组,这个新数组是由原数组变形衍生来的;而 forEach() 返回的是 undefined,所以是对原数组进行了改变操作。

    结论:map() 调用回调函数也不会改变原数组,forEach() 如果调用了回调函数会改变原数组。

    1.5 Performance Speed 执行效率

    执行效率上有细微差别。可执行以下代码查看:

    const myAwesomeArray = [1, 2, 3, 4, 5]
    
    const startForEach = performance.now()
    myAwesomeArray.forEach(x => (x + x) * 10000000000)
    const endForEach = performance.now()
    console.log(`Speed [forEach]: ${endForEach - startForEach} miliseconds`)
    
    const startMap = performance.now()
    myAwesomeArray.map(x => (x + x) * 10000000000)
    const endMap = performance.now()
    console.log(`Speed [map]: ${endMap - startMap} miliseconds`)
    

    以我的电脑为例:

    Speed [forEach]: 0.02500001573935151 miliseconds
    Speed [map]: 0.01999997766688466 miliseconds
    
    1.6 Final Thoughts 应用场景的思考
    • 如果是考虑修改或使用数据,可以使用 map(),因为会返回一个新的数组
    • 不使用数据的情况,推荐 forEach()

    2. All methods 所有数组实例方法

    有时候面试会被问到,有哪些数组实例的方法会改变原数组,哪些不会。数组 prototype 的所有方法如下:

    console 输入 Array.prototype

    2.1 改变原数组的方法
    方法名 功能 返回值
    unshift 首部添加 新数组长度
    push 尾部添加 新数组长度
    shift 首部删除 被删除元素
    pop 尾部删除 被删除元素,空数组返回 undefined
    splice(i, c, [n, m]) 通过删除或替换现有元素,或者原地添加新的元素来修改数组 被删除元素组成的数组
    sort 用原地算法对数组的元素进行排序,默认 Unicode 位点进行排序 排序后的数组
    reverse 将数组中元素的位置颠倒 颠倒后的数组
    forEach 对数组的每个元素执行一次提供的函数 undefined
    copyWithin(target[, start[, end]]) 浅复制数组的一部分到同一数组中的另一个位置 改变后的数组
    fill(val, [start, end)) 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。 修改后的数组
    includes 判断一个数组是否包含一个指定的值 包含则返回 true,否则返回 false
    2.2 不改变原数组的方法
    方法名 功能 返回值
    concat 用于合并两个或多个数组 返回新数组
    entries 返回一个新的Array Iterator对象 该对象包含数组中每个索引的键/值对,需要使用 iterableObj.next().value
    keys 返回一个新的 Array Iterator对象 该对象包含数组中每个索引键
    values 返回一个新的 Array Iterator对象 该对象包含数组中每个索引的值
    every 测试一个数组内的所有元素是否都能通过某个指定函数的测试 布尔值
    filter 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素 一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组
    find 查找满足条件的第一个元素 返回元素的值,若无返回 undefined
    findIndex 查找满足条件的第一个元素 返回元素的索引,若无返回 -1
    flat(depth) 扁平化嵌套数组或移除数组空项 一个包含将数组与子数组中所有元素的新数组
    flatMap arr.map(callback).flat(1) 几乎相同 一个新的数组,其中每个元素都是回调函数的结果,并且depth 值为1
    indexOf(searchE, fromIndex) findIndex 多一个参数,也是查找元素 返回元素的索引,若无返回 -1
    lastIndexOf 最后一个索引 返回元素的索引,若无返回 -1
    join(separator) 将一个数组或一个类数组对象的所有元素连接成一个字符串 返回拼接的字符串
    map 创建一个符合回调函数的数组 回调函数的结果
    slice([begin, end)) 一个由 begin 和 end 决定的原数组的浅拷贝 一个含有被提取元素的新数组

    3. 其他举例

    例(1)模糊查询,String 的 includes 结合 Array 的 filter 示例:

    var strs = ["back", "to", "basics"];
    console.log(strs.filter(str => str.includes("a"))); // ["back", "basics"]
    

    例(2)如下 JavaScript 代码运行后,b、c 的值分别是?

    var a = ["monkey", "elephant", "horse"];
    var b = a;
    var c = a.slice();
    a.push("panda");
    

    答案:

    b = ["monkey", "elephant", "horse", "panda"];
    c = ["monkey", "elephant", "horse"];
    

    a、b 指向同一个引用地址,c 的指向是 slice 创建的新数组。

    相关文章

      网友评论

          本文标题:JavaScript 回顾(一)map() 与 forEach(

          本文链接:https://www.haomeiwen.com/subject/jatkaqtx.html