作为一名合格的前端,js中的map是几乎每天都会写的函数,必须把它的来龙去脉
搞清楚,把它嚼碎后慢慢咀嚼然后咽下去,再配一杯82年的白开水 🛫️
打开 mdn 搜索一下 Array.prototype.map 可以看到 map 有两个形参,
第一个参数是一个回调函数,第二个参数是 this 指向,在第一个参数的函数中又包括三个行参,分别是元素项、索引、原数组;
map 的返回值是一个 新 的数组。
知道了怎么用,那我们大概来手写一个 map 来试试:
Array.prototype.my_map = function(fn, self){
let newArray = []
// 判断 fn 是否是函数 否则报错(为了跟 map 一样,报错尽量跟它一摸一样)
if(typeof fn !== 'function') throw `TypeError: ${fn} is not a function`
for(let i = 0; i < this.length; i++){
newArray.push(fn.call(self, this[i], i, this))
}
return newArray
}
// 测试1 通过😄
[1].map(v=>v+1) // [2]
[1].my_map(v=>v+1) // [2]
// 测试2 通过😊 提示语是类似了,这边原生的map会多提示具体报错的行数
[1].map('ss') // Uncaught TypeError: ss is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map('ss') // Uncaught TypeError: ss is not a function
简单的测试了一下,基本没什么问题 🎉,还是来系统测试一遍看看,js的类型都有以下
内容,我们来依次测试看看:
- null
- undefined
- Boolean
- Number
- BigInt
- String
- Object
- Array
- Function
- Symbol
- Date
// null ✅
[1].map(null) // Uncaught TypeError: null is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(null) // Uncaught TypeError: null is not a function
// undefined ✅
[1].map(undefined) // Uncaught TypeError: undefined is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(undefined) // Uncaught TypeError: undefined is not a function
// Boolean ✅
[1].map(Boolean) // [true]
[1].my_map(Boolean) // [true]
[1].map(true) // Uncaught TypeError: true is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(true) // Uncaught TypeError: true is not a function
[1].map(false) // Uncaught TypeError: false is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(false) // Uncaught TypeError: false is not a function
// Number ✅
[1].map(Number) // [1]
[1].my_map(Number) // [1]
[1].map(1) // Uncaught TypeError: 1 is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(1) // Uncaught TypeError: 1 is not a function
// BigInt ✅
[1].map(BitInt) // Uncaught ReferenceError: BitInt is not defined
// at <anonymous>:1:9
[1].my_map(BitInt) // Uncaught ReferenceError: BitInt is not defined
// at <anonymous>:1:12
[1].map(1n) // Uncaught TypeError: 1 is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(1n) // Uncaught TypeError: 1 is not a function
// String ✅
[1].map(String) // ['1']
[1].my_map(String) // ['1']
[1].map('a') // Uncaught TypeError: a is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map('a') // Uncaught TypeError: a is not a function
// Object ❌
[1].map(Object) // [Number]
[1].my_map(Object) // [Number]
[1].map({}) // Uncaught TypeError: #<Object> is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map({}) // Uncaught TypeError: [object Object] is not a function
// Array ❌
[1].map(Array) // [Array(3)]
[1].my_map(Array) // [Array(3)]
[1].map([]) // Uncaught TypeError: [object Array] is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map([]) // Uncaught TypeError: is not a function
// Function ✅
[1].map(Function) // Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
// at Function (<anonymous>)
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(Function) // Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
// at Function (<anonymous>)
// at Array.my_map (<anonymous>:6:26)
// at <anonymous>:1:5
[1].map(v=>v*2) // [2]
[1].my_map(v=>v*2) // [2]
// Symbol ❌
[1].map(Symbol) // [Symbol(1)]
[1].my_map(Symbol) // [Symbol(1)]
[1].map(Symbol('name')) // Uncaught TypeError: Symbol(name) is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(Symbol('name')) // Uncaught TypeError: Cannot convert a Symbol value to a string
// at Array.my_map (<anonymous>:4:54)
// at <anonymous>:1:5
// Date ❌
[1].map(Date) // ['Wed Jan 04 2023 23:00:52 GMT+0800 (中国标准时间)']
[1].my_map(Date) // ['Wed Jan 04 2023 23:00:52 GMT+0800 (中国标准时间)']
[1].map(new Date()) // VM1423:1 Uncaught TypeError: [object Date] is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(new Date()) // Uncaught TypeError: Wed Jan 04 2023 23:02:13 GMT+0800 (中国标准时间) is not a function
通过类型的测试后,基本没什么太大问题,就是提示语有些出入,对我们自己实现的 my_map
稍微调整下
Array.prototype.my_map = function(fn, self){
const type = Object.prototype.toString.call(fn)
let newArray = []
// 判断 fn 是否是函数 否则报错(为了跟 map 一样,报错尽量跟它一摸一样)
let warn = ''
// Object 这边提示语有点歧义🤔️
if(type.slice(8, -1) === 'Object')
warn = 'TypeError: #<Object> is not a function'
// Array
else if(type.slice(8, -1) === 'Array')
warn = `TypeError: ${type} is not a function`
// Symbol
else if(type.slice(8, -1) === 'Symbol')
warn = `TypeError: ${fn.toString()} is not a function`
else warn = `TypeError: ${fn} is not a function`
if(typeof fn !== 'function') throw warn
for(let i = 0; i < this.length; i++){
newArray.push(fn.call(self, this[i], i, this))
}
return newArray
}
// 再一次 Object ✅
[1].map({}) // Uncaught TypeError: #<Object> is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map({}) // Uncaught TypeError: #<Object> is not a function
// 再一次 Array ✅
[1].map([]) // Uncaught TypeError: [object Array] is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map([]) // Uncaught TypeError: [object Array] is not a function
// 再一次 Symbol ✅
[1].map(Symbol('name')) // Uncaught TypeError: Symbol(name) is not a function
// at Array.map (<anonymous>)
// at <anonymous>:1:5
[1].my_map(Symbol('name')) // Uncaught TypeError: Symbol(name) is not a function
调整完后基本可以实现 map 的效果,最后我们再来解释下 map 第二个参数具体是做什么的?🤔️
举个🌰:
const obj = {a: 2}
const fn = function(item) {
return item * this.a
}
[1].map(fn, obj) // [2]
[1].my_map(fn, obj) // [2]
想必看到这个🌰后,应该知道当前回调函数的 this 指向了 obj,
即可以调用 obj 内的属性了 ✌️
这边你可能还有疑问,如果第二个参数不传呢? 答案:this 指向 window
以上是个人的一些见解,如果有误,烦请帮忙指出 👉 十分感谢!
- 本文作者: MrRetro博客
- 本文链接: http://mrretro.gitee.io/retroblog/retroblog/2023/01/04/array/js数组中的map是怎么工作的/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!