解锁 JavaScript 魔力:不容错过的代码小妙招(三)
嘿,编程大侠们!在《解锁 JavaScript 魔力:不容错过的代码小妙招(二)》中,咱们已经在 JavaScript 的奇妙天地里挖到不少宝藏啦。现在,准备好再次启航,一头扎进 JavaScript 数组的神秘深海,去探寻那些像海底明珠般闪耀的超棒技巧。
一、Array.from ()—— 神奇数组变形侠
Array.from () 就像是一位拥有神奇魔法的数组变形侠,稳稳站在 JavaScript 的舞台中央。它可是静态方法里的大明星,能把那些像是等待变身的小精灵般的可迭代或类数组对象,华丽变身为全新的浅拷贝数组实例。
语法:
- Array.from(arrayLike)
- Array.from(arrayLike, mapFn)
- Array.from(arrayLike, mapFn, thisArg)
这里的 “arrayLike” 就如同渴望进化的小精灵,可能是类数组对象或者可迭代对象。“mapFn” 呢,好似一把能开启魔法之门的神秘钥匙(这可是个可选装备哦),它会作用于数组的每个元素,在元素加入新数组前,给它们来一场奇妙的改造之旅。而 “thisArg”(同样是个可选项),就像是 “mapFn” 施法时的神秘力量指引,默默为它保驾护航。
示例:
console.log(Array.from('handsome'))
// ['h', 'a', 'n', 'd', 's', 'o', 'm', 'e']
console.log(Array.from([1, 2, 3], (x) => x + x))
// [2, 4, 6]
它和 “map ()” 像是两个拥有相似超能力的伙伴,比如 “Array.from (obj, mapFn, thisArg)” 和 “Array.from (obj).map (mapFn, thisArg)” 能打出相同的效果。但咱这位变形侠可不会搞出中间数组这个小麻烦,而且 “mapFn” 只接收 “element” 和 “index” 这两位小伙伴作为参数,为啥呢?因为数组还在紧锣密鼓地构建之中呀。
描述:
当我们召唤 “Array.from ()” 时,如果只传入 “arrayLike” 参数,它就会像个温柔的工匠,轻松地把类数组或可迭代对象雕琢成数组。就好比对于字符串,它会把每个字符当作精美的玉石,小心翼翼地拆分成数组的元素。要是提供了 “mapFn”,那可就更厉害了,能在转换过程中像个创意大师,对每个元素进行个性化定制。比如说,有一个类数组对象表示的数字序列,想让它们都乘以 2 后组成新数组,“Array.from ()” 绝对能像超级英雄一样闪亮登场。而且因为它不会弄出中间数组这个小拖油瓶,在处理海量数据时,就像一辆轻便的跑车,在性能和内存使用的赛道上可能更具优势。
二、Array.prototype.at ()—— 酷炫索引魔杖
Array.prototype.at () 犹如一根在数组世界里闪闪发光的酷炫索引魔杖,不管是正数还是负数,只要你把索引数值像魔法咒语一样输入进去,它就能精准定位对应索引的元素。要是你输入的是负整数,嘿,它就像个聪明的小魔法师,从数组的最后一个元素开始倒着数。
语法:at(index),这里的 “index” 就是开启元素宝藏的索引密码(从零开始哦),并且它会自动变成整数。负数索引就像是从数组末尾出发的神秘导航,会访问 “index + array.length” 位置的元素。
示例:
const array1 = ['小明', '小红', '小兰']
let index = 2
console.log(array1.at(index))
// 小兰
index = -2
console.log(array1.at(index))
// 小红
在传递非负数时,它和括号表示法像是一对双胞胎,比如 “array [0]” 和 “array.at (0)” 都能把第一个元素乖乖带出来。但当需要从数组末端倒数时,它可比 “array [-1]” 这种容易让人误解成普通字符串属性的写法高明多了,就像一个专业的宝藏猎人,总能准确找到目标。
描述:
在 JavaScript 这片神秘大陆上,传统的数组索引访问方式对负数索引就像个迷路的小羊羔,不太友好,为啥呢?因为方括号内的表达式会被当作字符串属性处理。而 “at ()” 方法的出现,就像一盏明灯,让从数组末尾开始索引变得像走在平坦大道上一样简单直观。比如说在处理一些像栈操作模拟这种需要频繁访问数组末尾元素或倒数第几个元素的神秘任务,或者获取数据展示中的最新数据时,“at ()” 方法就像一把神奇的万能钥匙,能让代码像精美的艺术品一样简洁清晰,减少那些因索引计算错误而像小恶魔一样捣乱的潜在 bug。与其他获取特定索引元素的方法相比,它的语法简洁明了得就像清澈的溪流,大大提高了代码的可读性。
补充:比较不同的数组方法:
这个示例就像是一场数组魔法大比拼,比较了选择 Array 中倒数第二个元素的不同魔法招式。虽然下面显示的所有方法都能达到目的,但这个示例就像一个放大镜,凸显了 “at ()” 方法的简洁性和可读性。
const array = ['小明', '小红', '小兰']
// 使用长度属性
const lengthWay = array[array.length - 2]
console.log(lengthWay) // 小红
// 使用 slice() 方法。注意会返回一个数组
const sliceWay = array.slice(-2, -1)
console.log(sliceWay[0]) // 小红
// 使用 at() 方法
const atWay = array.at(-2)
console.log(atWay) // 小红
从这个例子可以看出,使用长度属性来获取倒数第二个元素就像在迷宫里找路,需要进行长度计算,代码相对复杂而且不够直观。“slice ()” 方法虽然也能完成任务,但它返回的是一个新数组,而不是单个元素,如果只是想要获取一个元素,还得像解开连环锁一样进行额外的索引访问操作。而 “at ()” 方法直接就能把倒数第二个元素像变魔术一样取出来,代码简洁易懂,就像一首优美的小诗。
三、Array.prototype.findIndex ()—— 执着索引探索者
Array.prototype.findIndex () 如同一位在数组丛林里执着探索的索引探险家,它会像个细心的寻宝猎人,在数组中仔细寻找满足特定测试函数的第一个元素的索引。要是没找到,也会像个诚实的使者,返回 -1。
语法:findIndex(callbackFn),这里的 “callbackFn” 就是为数组每个元素执行的神秘探索函数,它要像个信号灯一样返回一个真值,来表明找到了匹配元素,要是没找到就返回假值。调用时会传入 “element”(数组当前处理元素)、“index”(元素索引)、“array”(调用的数组本身)这几个得力助手。
示例:
const array = ['小明', '小红', '小兰']
const result = (element) => element === '小兰'
console.log(array.findIndex(result))
// 2
它是一种迭代方法里的勤劳小蜜蜂,按照索引升序逐个检查元素,一旦 “callbackFn” 像发现宝藏一样返回真值,就立刻停止遍历并返回该元素索引。
描述:
“findIndex ()” 方法在处理数组查找特定条件元素的索引时,就像一把锋利的宝剑,非常实用。与传统的循环遍历查找相比,它的代码简洁得像一阵清风,语义化程度高得像一篇优美的散文。比如说在一个存储用户数据的数组城堡里,想要找到年龄大于某个值的第一个用户的索引,只要轻松定义一个测试函数,然后像召唤精灵一样使用 “findIndex ()” 就能实现。而且由于它在找到第一个匹配元素后就像个果断的将军停止遍历,在一些数据量像大海一样庞大但满足条件的元素可能靠前的情况下,能像一艘快艇一样提高程序的执行效率。如果没有找到匹配元素,返回 -1 也方便后续的逻辑处理,就像留下了一个清晰的路标,可以根据这个返回值判断是否需要进行其他操作或者像个贴心的导游给出相应的提示信息。
四、Array.prototype.forEach ()—— 尽职元素遍历使者
Array.prototype.forEach () 好似一位在数组王国里尽职尽责的元素遍历使者,它会像个勤劳的小园丁,对数组的每个元素都执行一次给定的函数。
语法:forEach(callbackFn),这里的 “callbackFn” 就是为每个元素执行的魔法任务函数,它的返回值会像一阵轻烟被丢弃。调用时会传入 “element”(当前处理元素)、“index”(元素索引)、“array”(调用的数组)这些小伙伴。
示例旅程:
const array = ['小明', '小红', '小兰']
array.forEach((element) => console.log(element))
// 小明
// 小红
// 小兰
它按索引升序为每个元素调用一次函数,和 “map ()” 像是两个走在不同道路上的行者,它总是返回 “undefined”,不能像珍珠项链一样进行链式调用,通常用于链式调用末尾执行一些操作,就像一场演出的谢幕表演。
描述:
“forEach ()” 方法主要用于对数组中的每个元素执行一些像给花朵浇水施肥的副作用操作,比如打印元素、修改元素的某些属性等。它的简洁性在于不需要像个老管家一样手动管理索引变量,只需要像个专注的艺术家一样专注于对元素的操作逻辑。例如在更新一个包含多个对象的数组中每个对象的某个属性时,可以使用 “forEach ()” 像个灵巧的工匠方便地遍历数组并修改对象属性。虽然它不能像 “map ()” 那样像个魔法师创造出一个新的数组,但在一些不需要返回新数组的场景下,它能使代码像宁静的田园风光一样清晰可读。而且在一些函数式编程风格的代码中,它可以像演出的最后高潮一样作为最后一步来执行一些与数组元素相关的操作,如打印日志或者像点燃烟花一样触发一些异步操作等,避免了在循环中像乱麻一样混合过多不同类型的逻辑。
补充:将 for 循环转换为 forEach:
const array = ['小明', '小红', '小兰']
const copyItems = []
// for
for (let i = 0; i < array.length; i++) {
copyItems.push(array[i])
}
// forEach
array.forEach((item) => {
copyItems.push(item)
})
从这个例子可以看出,使用 “forEach ()” 可以像摆脱沉重的枷锁一样避免手动维护循环索引变量 “i”,使代码像轻盈的小鸟一样简洁,专注于元素的处理逻辑。对于一些简单的数组遍历操作,“forEach ()” 是一种更符合现代 JavaScript 编程风格的时尚选择。
五、Array.prototype.indexOf ()—— 敏锐元素位置侦探
Array.prototype.indexOf () 仿佛是一位在数组世界里目光如炬的敏锐元素位置侦探,它能像个精准的导航仪,返回数组中给定元素第一次出现的下标。要是这个元素像个调皮的小精灵躲起来了,不存在于数组中,它就会像个无奈的信使,返回 -1。
语法:
- indexOf(searchElement)
- indexOf(searchElement, fromIndex)
“searchElement” 就是要查找的元素宝藏,“fromIndex”(可选)是开始搜索的索引起点(从零开始哦),会像个听话的小助手转换为整数。负索引从末尾计数,如果 “fromIndex < -array.length” 或省略,就像从起点出发一样用 0 搜索整个数组;如果 “fromIndex >= array.length”,则像遇到了一堵墙一样不搜索并返回 -1。
示例追踪:
const array = ['小明', '小红', '小兰']
console.log(array.indexOf('小明'))
// 0
// 索引2开始,没有找到小红,返回-1
console.log(array.indexOf('小红', 2))
// -1
console.log(array.indexOf('小兰'))
// 2
它使用严格相等(就像 “===” 这个严格的裁判一样)比较元素,“NaN” 这个特殊的家伙永远不相等,所以查找 “NaN” 时总是像迷失在迷雾中一样返回 -1。而且在稀疏数组这个神秘花园里不能用它搜索空槽哦。
描述:
“indexOf ()” 是一个常用的数组查找方法,就像一把万能钥匙,用于确定特定元素在数组中的位置。它的优点在于简单直接,能够像闪电一样快速定位元素。在处理一些数据验证或者数据筛选的神秘任务时,如果需要判断某个元素是否像个忠诚的士兵存在于数组中,可以使用 “indexOf ()” 并根据返回值进行判断。例如在一个用户权限列表数组城堡里,检查某个特定权限是否存在,就可以使用 “indexOf ()”。对于从指定索引开始搜索的功能,在一些需要对数组部分区域像探索神秘岛屿一样进行查找的情况下非常有用,比如在处理分段数据或者已经排除了部分元素后的数组查找。而对于 “NaN” 的特殊处理,虽然在大多数情况下是合理的,但在涉及到可能包含 “NaN” 数据的数组处理时,需要像对待陷阱一样额外注意并可能需要结合其他方法来实现对 “NaN” 的查找需求。
补充:在稀疏数组中使用 indexOf ()
console.log(['小明',,'小红'].indexOf(undefined)) // -1
在稀疏数组中,“indexOf ()” 无法搜索空槽,这是因为它是基于元素值的严格相等比较,空槽并不等同于 “undefined”。所以在处理稀疏数组时,如果需要查找特定位置的元素或者判断某个元素是否在特定索引位置,可能需要像个智慧的学者考虑其他方法或者先对稀疏数组进行处理,将空槽转换为合适的值再使用 “indexOf ()”。
六、Array.prototype.map ()—— 卓越数组变换大师
Array.prototype.map () 无疑是一位站在数组艺术殿堂里的卓越数组变换大师,它能像个神奇的魔法工坊,创建一个新数组,这个新数组的元素是原数组每个元素像被施了魔法一样调用给定函数后的返回值。
语法:map(callbackFn),这里的 “callbackFn” 为每个元素执行的魔法函数,其返回值会像被点石成金一样成为新数组的元素,调用时会传入 “element”(当前处理元素)、“index”(元素索引)、“array”(调用的数组)这些魔法助手。
示例:
const array = ['1', '2', '3']
// 创建一个新数组,其中包含原始数组中的每个元素乘以2
const map = array.map((x) => x * 2)
console.log(map)
// [2, 4, 6]
它为数组每个元素像个魔法工匠一样调用函数并用结果构建新数组,是个强大的迭代方法里的王者。
描述:
“map ()” 方法在数据转换的魔法世界里发挥着重要作用。它允许我们以一种像编织精美绸缎一样简洁的方式对数组中的每个元素进行相同的操作,并像收集璀璨宝石一样收集结果形成一个新数组。这在数据格式化、数据预处理等像魔法仪式一样的方面非常常见。例如,将一个包含数字的数组像施了魔法一样转换为它们的平方数组成的新数组,或者将一个包含字符串的数组像被仙女棒点过一样转换为大写形式的新数组等。与传统的循环遍历并手动构建新数组相比,“map ()” 不仅代码像优雅的舞蹈一样简洁,而且更符合函数式编程的思想,使得代码的逻辑像明亮的灯塔一样清晰,易于理解和维护。同时,由于它像个善良的守护者返回一个新数组,原数组不会像被破坏的城堡一样被修改,这在很多需要像珍藏宝藏一样保留原始数据的情况下非常重要,避免了因数据修改而像恶魔入侵一样导致的潜在错误和逻辑混乱。
总之,这些数组相关的小技巧如同 JavaScript 数组世界里的璀璨星辰,熟练掌握它们,能让你的代码在处理数组时像在魔法森林里自由穿梭的精灵一样游刃有余,充满无限可能。快来将它们融入你的编程魔法吧!