ES2023新特性!

  • findLast()和findLastIndex()
  • Hashbang语法
  • Symbol作为WeakMap的key
  • 复制改变数组

findLast()和findLastIndex()

Array.prototype.findLast()

findLast() 方法反向迭代数组,并返回满足提供的测试函数的第一个匹配的元素。如果没有找到对应元素,则返回 undefined。

const array1 = [5, 12, 50, 130, 44];

const found = array1.findLast((element) => element > 45);

console.log(found);
// Expected output: 130

语法

findLast(callbackFn)
findLast(callbackFn, thisArg)
参数

callbackFn: 数组中测试元素的函数,找到匹配的元素会返回true,否则返回false,函数在被调用时会传递以下参数:
element: 当前遍历到的元素。
index:当前遍历元素的索引。
array:调用findLast()的数组本身。

thisArg:执行callbackFn时的this。

返回值

满足提供的测试函数的第一个匹配的元素。

描述

findLast() 是一个迭代方法。该方法对数组从后到前执行 callbackFn 函数,直到 callbackFn 返回true。然后 findLast() 返回该元素并停止遍历数组。如果 callbackFn 遍历完数组也没找到匹配元素,则 findLast() 返回 undefined。

callbackFn 会被数组中的每个元素调用,而不仅仅是那些被赋值的元素。对于稀疏数组来说(含有empty),空槽行为和 undefined 相同。

findLast() 方法不会改变调用它的数组,但是提供的 callbackFn 可以。但是请注意,数组的长度是在第一次调用 callbackFn 之前保存的。因此:

  • callbackFn 不会访问在调用 findLast() 开始后才添加到数组中的任何元素。
  • 给已访问过的索引重新赋值将不会被 callbackFn 重新访问。
  • 如果 callbackFn 更改了数组中现有的、尚未访问的元素,则其传递给 callbackFn 的值将是 findLast() 访问该元素索引时的值。已删除的元素会被当做 undefined 来访问。

注意: 以上描述的并发修改的情况经常导致难以理解的代码,通常应该避免(特殊情况除外)。

示例

查找与元素属性匹配的数组中的最后一个对象
const inventory = [
  { name: "apples", quantity: 2 },
  { name: "bananas", quantity: 0 },
  { name: "fish", quantity: 1 },
  { name: "cherries", quantity: 5 },
];

// 库存低时返回 true
function isNotEnough(item) {
  return item.quantity < 2;
}

console.log(inventory.findLast(isNotEnough));
// { name: "fish", quantity: 1 }
使用箭头函数和解构
const inventory = [
  { name: "apples", quantity: 2 },
  { name: "bananas", quantity: 0 },
  { name: "fish", quantity: 1 },
  { name: "cherries", quantity: 5 },
];

const result = inventory.findLast( ({ quantity }) => quantity < 2 );

console.log(result)
// { name: "fish", quantity: 1 }
查找数组中的最后一个素数
function isPrime(element) {
  if (element % 2 === 0 || element < 2) {
    return false;
  }
  for (let factor = 3; factor <= Math.sqrt(element); factor += 2) {
    if (element % factor === 0) {
      return false;
    }
  }
  return true;
}

console.log([4, 6, 8, 12].findLast(isPrime)); // undefined,没有找到
console.log([4, 5, 7, 8, 9, 11, 12].findLast(isPrime)); // 11
在稀疏数组上使用 findLast()

稀疏数组中的空槽访问,并被视为 undefined

// 声明一个在索引 2、3 和 4 处没有元素的数组
const array = [0, 1, , , , 5, 6];

// 显示所有的索引(不只包括那些被赋值的)
array.findLast((value, index) => {
  console.log(`访问索引 ${index},值为 ${value}`);
});
// 访问索引 6,值为 6
// 访问索引 5,值为 5
// 访问索引 4,值为 undefined
// 访问索引 3,值为 undefined
// 访问索引 2,值为 undefined
// 访问索引 1,值为 1
// 访问索引 0,值为 0

// 显示所有的索引(包括已被删除的)
array.findLast((value, index) => {
  // 在第一次迭代时删除值为 5 的元素
  if (index === 6) {
    console.log(`删除值为 array[5],其值为 ${array[5]}`);
    delete array[5];
  }
  // 元素 5 在被删除后,仍会被访问
  console.log(`访问索引 ${index},值为 ${value}`);
});
// 删除值为 array[5],其值为 5
// 访问索引 6,值为 6
// 访问索引 5,值为 undefined
// 访问索引 4,值为 undefined
// 访问索引 3,值为 undefined
// 访问索引 2,值为 undefined
// 访问索引 1,值为 1
// 访问索引 0,值为 0
在非数组对象上调用 findLast()
const arrayLike = {
  length: 3,
  0: 2,
  1: 7.3,
  2: 4,
};
console.log(
  Array.prototype.findLast.call(arrayLike, (x) => Number.isInteger(x)),
); // 4

Array.prototype.findLastIndex()

findLastIndex() 方法反向迭代数组,并返回满足所提供的测试函数的第一个元素的索引。若没有找到对应元素,则返回 -1。

const array1 = [5, 12, 50, 130, 44];

const isLargeNumber = (element) => element > 45;

console.log(array1.findLastIndex(isLargeNumber));
// Expected output: 3
// Index of element with value: 130

语法

findLastIndex(callbackFn)
findLastIndex(callbackFn, thisArg)
参数

callbackFn:对数组中的每个元素执行的函数。若找到匹配的元素,回调返回true,否则返回false。函数在被调用时会传递以下参数:

element:当前遍历到的元素。

index:当前正在处理的元素的索引。

array:调用 findLastIndex() 的数组本身。

thisArg:执行 callbackFn 时的this。

返回值

数组中通过测试的最后一个(索引最大)元素的索引。如果没有找到任何匹配的元素,则返回 -1。

描述

findLastIndex() 方法是一个迭代方法。它为数组倒序调用提供的 callbackFn 函数,直到 callbackFn 返回true。然后 findLastIndex() 返回元素的索引并且停止遍历数组。如果遍历完数组 callbackFn 也没有返回true,则 findLastIndex() 返回 -1。

示例

在稀疏数组上使用 findLastIndex()
console.log([1, , 3].findLastIndex((x) => x === undefined)); // 1

Hashbang 注释

Hashbang 注释是一种特殊的注释语法,其行为与单行注释(//)完全一样,只是它以 #! 开头,并且只在脚本或模块的最开始处有效。注意,#! 标志之前不能有任何空白字符。注释由 #! 之后的所有字符组成直到第一行的末尾;只允许有一条这样的注释。JavaScript 中的 hashbang 注释类似于 Unix 中的 shebang,它提供了一个特定的 JavaScript 解释器的路径,你想用它来执行这个脚本。在 hashbang 注释标准化之前,它已经在非浏览器主机(如 Node.js)中得到了事实上的实现,在那里,它在被传递给引擎之前被从源文本中剥离。示例如下:

#!/usr/bin/env node

console.log("Hello world");

JavaScript 的解释器会把它视为普通注释——只有当脚本直接在 shell 中运行时,它对 shell 才有语义意义。

你只能使用 #! 注释样式以指定 JavaScript 解释器。在所有其他情况下,只需使用 // 注释(或多行注释)。

Symbol作为WeakMap的key

在 JavaScript 中,Object和Symbol是保证唯一并且不能重新创建的,这使得它们都是 WeakMap 键的绝佳选择。 以前的版本或规范只允许使用Object,但幸运的是最新提出的将Symbol作为 WeakMap 键的提案将非注册Symbol添加到允许的键列表中。

const weak = new WeakMap();
const key = Symbol("ref");
weak.set(key, "ECMAScript 2023");

console.log(weak.get(key));
// ECMAScript 2023

通过复制改变数组

Array.prototype上的reverse()、sort()和splice()会改变原数组。于是新提案提出了toReversed()、toSorted()、toSpliced()和with()。

Array.prototype.toReversed()

reverse() 方法对应的复制版本。它返回一个包含以相反顺序排列元素的新数组。

示例

反转数组中的元素
const items = [1, 2, 3];
console.log(items); // [1, 2, 3]

const reversedItems = items.toReversed();
console.log(reversedItems); // [3, 2, 1]
console.log(items); // [1, 2, 3]
在稀疏数组上使用 toReversed()
console.log([1, , 3].toReversed()); // [3, undefined, 1]
console.log([1, , 3, 4].toReversed()); // [4, 3, undefined, 1]
在非数组对象上调用 toReversed()
const arrayLike = {
  length: 3,
  unrelated: "foo",
  2: 4,
};
console.log(Array.prototype.toReversed.call(arrayLike));
// [4, undefined, undefined]
// '0' 和 '1' 两个索引不存在,所以它们会变成 undefined

Array.prototype.toSorted()

sort() 方法的复制方法版本。它返回一个新数组,其元素按升序排列。

// 不传入函数
toSorted()

// 传入箭头函数
toSorted((a, b) => { /* … */ })

// 传入比较函数
toSorted(compareFn)

// 內联比较函数
toSorted(function compareFn(a, b) { /* … */ })
参数

compareFn:指定一个定义排序顺序的函数。如果省略,则将数组元素转换为字符串,然后根据每个字符的 Unicode 码位值进行排序。

a:用于比较的第一个元素。

b:用于比较的第二个元素。

示例

对数组进行排序
const months = ["Mar", "Jan", "Feb", "Dec"];
const sortedMonths = months.toSorted();
console.log(sortedMonths); // ['Dec', 'Feb', 'Jan', 'Mar']
console.log(months); // ['Mar', 'Jan', 'Feb', 'Dec']

const values = [1, 10, 21, 2];
const sortedValues = values.toSorted((a, b) => a - b));
console.log(sortedValues); // [1, 2, 10, 21]
console.log(values); // [1, 10, 21, 2]

在稀疏数组上使用 toSorted()

空槽被视为具有 undefined 值而被排序。它们总是排序到数组的末尾,并且 compareFn 不会对它们进行调用。

console.log(["a", "c", , "b"].toSorted()); // ['a', 'b', 'c', undefined]
console.log([, undefined, "a", "b"].toSorted()); // ["a", "b", undefined, undefined]
在非数组对象上调用 toSorted()

toSorted() 方法会读取 this 的 length 属性。然后它会收集所有在 0 到 length - 1 范围内的整数键属性,对它们进行排序并将它们写入一个新的数组中。

const arrayLike = {
  length: 3,
  unrelated: "foo",
  0: 5,
  2: 4,
};
console.log(Array.prototype.toSorted.call(arrayLike));
// [4, 5, undefined]

Array.prototype.toSpliced()

splice() 方法的复制版本。它返回一个新数组,并在给定的索引处删除和/或替换了一些元素。

toSpliced(start)
toSpliced(start, deleteCount)
toSpliced(start, deleteCount, item1)
toSpliced(start, deleteCount, item1, item2, itemN)
参数

start:从 0 开始计算的索引,表示要开始改变数组的位置,它会被转换为整数。

  • 如果 start < 0,则从数组末尾开始计数,使用 start + array.length
  • 如果 start < -array.length 或者省略了 start,则使用 0
  • 如果 start >= array.length,不会删除任何元素,但该方法将表现为添加元素的函数,添加提供的所有元素

deleteCount:可选,一个整数,指示数组中要从 start 删除的元素数量。如果 deleteCount 被省略了,或者如果它的值大于或等于由 start 指定的位置到数组末尾的元素数量,将会删除从 start 到数组末尾的所有元素。但是,如果你想要传递任何 itemN 参数,则应向 deleteCount 传递 Infinity 值,以删除 start 之后的所有元素,因为显式的 undefined 会转换为 0。

如果 deleteCount 是 0 或者负数,则不会删除元素。在这种情况下,你应该指定至少一个新元素(见下文)。

item1, …, itemN:可选,元素将从 start 开始添加到数组当中。如果你没有指定任何元素,toSpliced() 只会从数组中删除元素。

示例

删除、添加和替换元素

比使用 slice() 和 concat() 更高效。

const months = ["Jan", "Mar", "Apr", "May"];

// 在索引 1 处添加一个元素
const months2 = months.toSpliced(1, 0, "Feb");
console.log(months2); // ["Jan", "Feb", "Mar", "Apr", "May"]

// 从第 2 个索引开始删除两个元素
const months3 = months2.toSpliced(2, 2);
console.log(months3); // ["Jan", "Feb", "May"]

// 在索引 1 处用两个新元素替换一个元素
const months4 = months3.toSpliced(1, 1, "Feb", "Mar");
console.log(months4); // ["Jan", "Feb", "Mar", "May"]

// 原数组不会被修改
console.log(months); // ["Jan", "Mar", "Apr", "May"]

Array.prototype.with()

使用方括号表示法修改指定索引值的复制方法版本。它会返回一个新数组,其指定索引处的值会被新值替换。原数组不会被修改。

array.with(index, value)
参数

index:要修改的数组索引(从 0 开始),将会转换为整数。

  • 负数索引会从数组末尾开始计数——即当 index < 0 时,会使用 index + array.length
  • 如果规范化后的索引超出数组边界,会抛出 RangeError。

value:要分配给指定索引的任何值。

示例

创建一个新的数组,改变其中一个元素
const arr = [1, 2, 3, 4, 5];
console.log(arr.with(2, 6)); // [1, 2, 6, 4, 5]
console.log(arr); // [1, 2, 3, 4, 5]
数组方法的链式调用

在更新一个数组元素后继续调用其他的数组方法。

const arr = [1, 2, 3, 4, 5];
console.log(arr.with(2, 6).map((x) => x ** 2)); // [1, 4, 36, 16, 25]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值