by Pradeep Pothineni

通过Pradeep Pothineni

array.prototype.map()如何工作 (How array.prototype.map() works)

JavaScript is an ubiquitous language now. Once confined to client side usage, now you can find it on servers in many flavors. As JavaScript grew, so did its arsenal of functions that users can use. Most times you are content using these methods and only rarely will you want to take that extra step to understand what is really going on under the hood.

JavaScript现在是一种无处不在的语言。 一旦局限于客户端使用,现在您可以在服务器上以多种方式找到它。 随着JavaScript的发展,其用户可以使用的功能库也随之增加。 在大多数情况下,您对使用这些方法感到满意,并且很少会想要采取额外的步骤来了解实际情况。

On that note, let’s take that extra step today and explore a very popular function: Array.prototype.map().

关于这一点,让我们今天采取额外的步骤,并探索一个非常受欢迎的函数: Array.prototype.map()

Disclaimer: I won’t be explaining how to use map() the below example illustrates it, or you can find numerous examples when you google. Instead, let’s dwell into how map actually gets implemented behind the scenes.

免责声明 :我不会解释如何使用map() -以下示例进行了说明,或者在使用google时可以找到许多示例。 相反,让我们研究一下如何在后台实际实现地图。

The map() method creates a new array with the result of calling a provided function on every element in the calling array.

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

Example:

例:

var array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);console.log(map1);
// expected output: Array [2, 8, 18, 32]

实作 (Implementation)

Let’s pick the implementation right from the horse’s mouth and try dissecting it. Below is the MDN polyfill. Spend some time understanding the code and copy it and run it on your machine. If you are a beginner/intermediate JavaScript developer, you will surely run into at least couple of questions.

让我们从马口中选择实现,然后尝试剖析它。 以下是MDN polyfill。 花一些时间来理解代码并复制并在您的计算机上运行它。 如果您是初学者/中级JavaScript开发人员,那么您肯定会遇到至少两个问题。

/*Array.prototype.map implementation*/
Array.prototype.map = function (callback/*, thisArg*/) {var T, A, k;if (this == null) {throw new TypeError('this is null or not defined');}var O = Object(this);var len = O.length >>> 0;if (typeof callback !== 'function') {throw new TypeError(callback + ' is not a function');}if (arguments.length > 1) { T = arguments[1];}A = new Array(len);k = 0;while (k < len) {var kValue, mappedValue;if (k in O) {kValue = O[k];mappedValue = callback.call(T, kValue, k, O);            A[k] = mappedValue;}k++;}return A;
};

I have highlighted few common questions that might arise in the code comments below.

我强调了以下代码注释中可能出现的一些常见问题。

/*Array.prototype.map implementation*/
Array.prototype.map = function (callback/*, thisArg*/) {var T, A, k;if (this == null) {throw new TypeError('this is null or not defined');}var O = Object(this);var len = O.length >>> 0;// QUESTION 1 : What is the need for this line of code?if (typeof callback !== 'function') {throw new TypeError(callback + ' is not a function');}if (arguments.length > 1) { T = arguments[1];}//  QUESTION 2 :What is the need for the if condition and why are we assiging T=arguments[1]?A = new Array(len);k = 0;while (k < len) {var kValue, mappedValue;if (k in O) {kValue = O[k];mappedValue = callback.call(T, kValue, k, O); // QUESTION 3: why do we pass T,k and O when all you need is kvalue?A[k] = mappedValue;}k++;}return A;
};

Let’s address each of them starting from the bottom

让我们从底部开始解决每个问题

QUESTION 3: Why do we pass T,k and O when all you need is kValue?

问题3:当您只需要kValue时,为什么要传递T,k和O?

mappedValue = callback.call(T, kValue, k, O);

This is the simplest of the three questions so I have picked this to start with. In most cases, passing the kValue to the callback would be sufficient but:

这是三个问题中最简单的一个,因此我首先选择了这个问题。 在大多数情况下,将kValue传递给回调就足够了,但是:

  • What if you have a use case where you need to perform an operation only on every other element? Well, you need an index which is (k).

    如果有一个用例,您只需要对其他所有元素执行操作,该怎么办? 好吧,您需要的索引是(k)

  • Similarly there could be other use cases where you need the array (O) itself to be available in the callback.

    同样,在其他用例中,您需要数组(O)本身在回调中可用。

  • Why T? For now just know that T is being passed around to maintain context. You will understand this better once you are done with question 2.

    为什么是T ? 现在,只需知道T正在传递以维护上下文即可。 完成问题2后,您将更好地理解这一点。

QUESTION 2 :What is the need for the if condition and why are we assigning T=arguments[1]?

问题2:if条件需要什么?为什么要分配T = arguments [1]?

if (arguments.length > 1) {   T = arguments[1];    }

The map function in the above implementation has two arguments: the callback and the optional thisArg. Callback is a mandatory argument whereas thisArg is optional.

上述实现中的map函数具有两个参数: callback和可选的thisArg 回调是必填参数,而thisArg是可选参数。

One can pass what should be the “this” value inside the callback by providing the second optional argument. This is why the code checks if there is more than one argument and assigns the second optional argument to a variable that can be passed on to the callback.

通过提供第二个可选参数,可以在回调内部传递应为“ this”的值。 这就是为什么代码检查是否存在多个参数并将第二个可选参数分配给可以传递给回调的变量的原因。

To illustrate better, let’s say you have a mock requirement where you need to return the number/2 if it is divisible by 2, and if it is not divisible by 2, you need to return the username of the calling person. The below code illustrates how you can make this happen:

为了更好地说明,我们假设您有一个模拟要求,如果要将该数字/ 2整除为2,则需要返回该数字/ 2,如果不能被2整除,则需要返回主叫方的用户名。 下面的代码说明了如何实现此目的:

const myObj = { user: "John Smith" }
var x = [10, 7];
let output = x.map(function (n) {if (n % 2 == 0) {return n / 2;} else {return this.user}
}, myObj) // myObj is the second optional argument arguments[1]console.log(output); // [5,'John Smith']
//if you run the program without supplying myObj it would be //undefined as it cannot access myObj values
console.log(output); // [ 5, undefined ]

QUESTION 1: What is the need for this line of code?

问题1:这行代码需要什么?

var len = O.length >>> 0

This one took some time for me to figure out. There is a lot going on in this line of code. In JavaScript, you have the ability to redefine the “this” within a function by invoking the method using call. You can do this using bind or apply as well, but for this discussion lets stick with call.

我花了一些时间才弄清楚。 这行代码中发生了很多事情。 在JavaScript中,您可以通过使用call调用方法来在函数中重新定义“ this” 您也可以使用绑定应用来执行此操作,但是在此讨论中,我们坚持通话。

const anotherObject={length:{}}
const myObj = { user: "John Smith" }
var x = [10, 7];
let output = x.map.call(anotherObject,function (n) {if (n % 2 == 0) {return n / 2;}else {return this.user}
}, myObj)

When you invoke using call,the first parameter would be the context in which the map function executes. By sending the parameter, you are overwriting the “this” inside the map with the “this” of anotherObject.

当您使用通话进行调用时, 第一个参数将是map函数在其中执行的上下文。 通过发送参数,你与anotherObject的“这个”覆盖“这个”里面的地图。

If you observe, the length property of the anotherObject is an empty object and not an integer. If you just use O.length instead of O.length>>>0 it would result in an undefined value. By zero shifting, you are actually converting any fractions and non integers to an integer. In this case the result would be coerced to 0.

如果您观察到,anotherObject的length属性是一个空对象,而不是整数。 如果仅使用O.length而不是O.length> >> 0,则将导致未定义的值。 通过零移位,实际上是将任何分数和非整数转换为整数。 在这种情况下,结果将强制为0。

Most use cases won’t need this check, but there might be an edge case where this kind of scenario needs to be handled. The good programmers who designed the specification really did think it through! Talking about the specification, you can actually find the specification on how each function has to be implemented in Ecmascript here:

大多数用例不需要进行此检查,但是在某些极端情况下,需要处理这种情况。 设计该规范的优秀程序员确实认真考虑了! 在谈论规范时,您实际上可以在以下位置找到有关如何在Ecmascript中实现每个功能的规范:

ECMAScript Language Specification - ECMA-262 Edition 5.1This document and possible translations of it may be copied and furnished to others, and derivative works that comment…www.ecma-international.org

ECMAScript语言规范-ECMA-262版本5.1 本文档及其可能的翻译版本可以复制并提供给他人,以及带有注释的衍生作品…… www.ecma-international.org

The spec (step 3) clearly says that the length has to be a 32 bit unsigned integer. This is the reason we are zero fill shifting to ensure that length is an integer, as map itself does not require that the this value be an Array object.

规范( 第3步 )明确指出该长度必须是32位无符号整数。 这就是我们进行零填充移位以确保长度为整数的原因,因为map本身并不要求this值为Array对象。

That’s it!

而已!

I would like to thank couple of people, i never met them but they were kind enough to take time (in internet forums) and help me understand few nuances.

我要感谢几个人,我从没见过他们,但是他们很友好,可以花些时间(在互联网论坛上)并帮助我理解一些细微差别。

Salathiel Genese, Jordan Harband — thank you!

撒拉杰尼斯 , 乔丹Harband -谢谢!

Note: If you are stuck on a different line of code, feel free to put that in the comments and I will do my best to clarify.

注意:如果您停留在不同的代码行中,请随时在注释中注明,我将尽力澄清。

Thank you for your time and happy coding!

感谢您的时间和愉快的编码!

翻译自: https://www.freecodecamp.org/news/how-array-prototype-map-works-b6b69379c3af/

array.prototype.map()如何工作相关推荐

  1. Array.prototype.map() 、 Array.prototype.reduce()、Array.prototype.filter()

    文章目录 1. map 2. reduce 3. filter 1. map   map 函数接收一个回调函数作为参数,然后返回一个数组,这个数组中的每个元素都是调用回调函数后返回的结果.如: fun ...

  2. 前端Array.prototype.map()使用案例和forEach使用接口案例

    目录 官网 map定义 实例 案例 未修改前 map修改后 代码 forEach定义 案例 未修改前 修改后 代码 map和forEach区别 最后 官网 MDN map定义 map() 方法创建一个 ...

  3. 【JavaScript笔记 · 基础篇(五)】Array全家桶(引用数据类型中的数组 / Array对象 / Array.prototype)

    文章目录 一. 引用数据类型中的数组 1.1 概述 1.2 初始化 1.2.1 字面量 1.2.2 构造函数模式 1.3 访问 1.4 length属性 1.5 数组遍历 1.6 类数组对象 1.6. ...

  4. JS中集合对象(Array、Map、Set)及类数组对象的使用与对比

    JS中集合对象(Array.Map.Set)及类数组对象的使用与对比 在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java ...

  5. Array.prototype.slice.call()如何工作?

    本文翻译自:how does Array.prototype.slice.call() work? 我知道它用于使参数成为一个真正的数组,但我不明白使用Array.prototype.slice.ca ...

  6. 小程序 array.map_Array.map解释了4个复杂级别:从5岁到功能程序员。

    小程序 array.map Array.map might be JavaScript's most useful function. Forgoing it nowadays is like don ...

  7. es6 迭代器(遍历器)Iterator 自定义遍历器 lterator/简单模拟values方法 for of运行机制 Array/Set/Map默认迭代器接口 对象设置迭代器

    文章目录 迭代器 Iterator 用处 (需要自定义遍历数据的时候) 自定义 遍历器 lterator 简单模拟values方法 Array Set Map 默认迭代器接口 entries valu ...

  8. Array.prototype.reduce 的理解与实现

    Array.prototype.reduce 是 JavaScript 中比较实用的一个函数,但是很多人都没有使用过它,因为 reduce 能做的事情其实 forEach 或者 map 函数也能做,而 ...

  9. Array.prototype.slice Array.prototype.splice 用法阐述

    目的 对于这两个数组操作接口,由于不理解, 往往被误用, 或者不知道如何使用.本文尝试给出容易理解的阐述. 数组 什么是数组? 数组是一个基本的数据结构, 是一个在内存中依照线性方式组织元素的方式, ...

最新文章

  1. 深入分析Java的序列化与反序列化
  2. Mybatis Plus 是如何实现动态 SQL 语句的?原理你懂吗?
  3. 计算机英语基础性考任务三,(2021更新)国家开放大学电大《计算机应用基础》形考任务3作业3试题及答案...
  4. 目标检测 nms非极大抑制算法
  5. Struts2_HelloWorld_2
  6. Nagios学习实践系列
  7. ue 抗锯齿 渲染序列失灵_最大的锯齿形序列
  8. c gui qt 4编程第二版_我的QT5学习之路(一)——浅谈QT的安装和配置
  9. 2021年中国助行靴市场趋势报告、技术动态创新及2027年市场预测
  10. exchange系列(一)exchange2010邮件服务器的安装与规划
  11. Win10怎么备份系统
  12. MS印象-----北京.Net俱乐部8.13活动
  13. codevs——1436 孪生素数 2
  14. PostgreSQL数据库统计信息——analyze大致流程
  15. 我的生活所感悟出的杂句
  16. 咸鱼Maya笔记—摄影表
  17. 修正米勒编码matlab,修正米勒编码信源解码电路及其解码方法和节能控制方法
  18. tui-editor富文本编辑器组件
  19. 带你轻松认识SSL协议中的加密套件
  20. 想一想就感觉到生活还是充满很多正能量的

热门文章

  1. http库cookiejar模块
  2. css 浮动效果 0302
  3. django-模板的功能与配置
  4. .net发送邮件outlook中文乱码
  5. Climbing Stairs leetcode java
  6. 好记性不如烂笔杆-android学习笔记十一 Service的应用
  7. Agile PLM EC Understand the BOM Publishing Process
  8. 再见 XShell 和 ITerm 2,是时候拥抱全平台高颜值终端工具 Hyper 了!
  9. 科普文:为什么不能在服务器上 npm install ? #30
  10. 面试官系统精讲Java源码及大厂真题 - 33 CountDownLatch、Atomic 等其它源码解析