JavaScript内核与高级编程之:`JavaScript`的`at()` Method:其在 `JavaScript` 数组和字符串中从后向前索引的用法。

各位观众老爷,今天咱们来聊聊 JavaScript 里一个挺好使的小玩意儿:at() 方法。这玩意儿啊,就像一把瑞士军刀,在数组和字符串里都能用,尤其是从后往前索引的时候,那叫一个方便。

开场白:索引的那些事儿

话说,咱们写代码,免不了要跟数组和字符串打交道。要从里面掏东西,最常用的就是索引了。比如,你要数组里第一个元素,arr[0],简单粗暴。要字符串里第三个字符,str[2],也很直接。

但是,如果我想拿最后一个元素呢?一般咋办?arr[arr.length - 1],对吧?看着是不是有点长?要是再复杂点,想拿倒数第三个,arr[arr.length - 3],这公式越写越长,容易把自己绕晕。

这时候,at() 方法就派上用场了。它可以让你用负数索引,直接从后往前数,简洁明了,妈妈再也不用担心我的数学了!

at() 方法的基本用法

at() 方法接收一个整数作为参数,表示要访问的元素的索引。正数索引和咱们平时用的没啥区别,0是第一个,1是第二个,以此类推。关键在于负数索引,-1表示最后一个,-2表示倒数第二个,以此类推。

数组里的 at()

先来看看在数组里怎么用。

const arr = ['apple', 'banana', 'cherry', 'date'];

console.log(arr.at(0));   // 输出: apple (第一个元素)
console.log(arr.at(2));   // 输出: cherry (第三个元素)
console.log(arr.at(-1));  // 输出: date (最后一个元素)
console.log(arr.at(-2));  // 输出: cherry (倒数第二个元素)

// 和 arr[arr.length - 1] 效果一样
console.log(arr.at(-1) === arr[arr.length - 1]); // 输出: true

// 越界了?没关系,返回 undefined
console.log(arr.at(10));  // 输出: undefined
console.log(arr.at(-10)); // 输出: undefined

你看,是不是很方便?不用算长度,直接用负数索引就能拿到倒数的元素。而且,如果索引越界了,at() 方法会返回 undefined,不会像 arr[index] 那样,有时会抛出错误。

字符串里的 at()

字符串也能用 at() 方法,用法和数组几乎一样。

const str = 'Hello, world!';

console.log(str.at(0));   // 输出: H (第一个字符)
console.log(str.at(7));   // 输出: w (第八个字符)
console.log(str.at(-1));  // 输出: ! (最后一个字符)
console.log(str.at(-6));  // 输出: o (倒数第六个字符)

// 和 str[str.length - 1] 效果一样
console.log(str.at(-1) === str[str.length - 1]); // 输出: true

// 越界了?还是 undefined
console.log(str.at(100)); // 输出: undefined
console.log(str.at(-100)); // 输出: undefined

字符串用 at() 方法,就像用数组一样,方便快捷。

at() vs []

可能有人会问了,既然 arr[index] 也能访问数组元素,str[index] 也能访问字符串字符,那为啥还要用 at() 呢?它们有什么区别?

主要区别就在于越界时的行为

特性 [] 访问方式 at() 方法
越界访问数组 返回 undefined 返回 undefined
越界访问字符串 返回 undefined 返回 undefined
负数索引 不支持 支持

看起来好像 [] 也没啥问题啊,都能返回 undefined,那咱们再深入一点。

在某些特殊情况下,直接使用 [] 访问数组或字符串,如果索引超出了范围,或者索引不是数字,可能会导致一些意想不到的错误,尤其是在严格模式下。虽然现代浏览器对这些情况处理得比较好,但 at() 方法的明确性和安全性更高。

at() 方法的优势

  1. 可读性更好:使用负数索引,可以更直观地表达“倒数第几个”的意思,代码更易读。
  2. 安全性更高at() 方法对于越界情况的处理更加一致,始终返回 undefined,避免了一些潜在的错误。
  3. 语法更简洁:访问数组或字符串的最后一个元素,arr.at(-1)arr[arr.length - 1] 更简洁。

at() 方法的应用场景

  1. 获取数组或字符串的最后一个元素:这是 at() 方法最常见的应用场景。

    function getLastElement(arr) {
      return arr.at(-1);
    }
    
    const numbers = [1, 2, 3, 4, 5];
    console.log(getLastElement(numbers)); // 输出: 5
  2. 循环处理数组或字符串,需要访问倒数元素

    function processString(str) {
      let result = '';
      for (let i = 0; i < str.length; i++) {
        // 访问当前字符和倒数第 i 个字符
        result += str.at(i) + str.at(-i - 1);
      }
      return result;
    }
    
    console.log(processString('abcde')); // 输出: aeedbcdccbab
  3. 处理动态数组,需要根据相对位置访问元素

    function getRelativeElement(arr, offset) {
      // offset 可以是正数或负数,表示相对于数组末尾的偏移量
      return arr.at(arr.length - 1 + offset);
    }
    
    const data = [10, 20, 30, 40, 50];
    console.log(getRelativeElement(data, 0));   // 输出: 50 (最后一个元素)
    console.log(getRelativeElement(data, -1));  // 输出: 40 (倒数第二个元素)
    console.log(getRelativeElement(data, -3));  // 输出: 20 (倒数第四个元素)

兼容性问题

at() 方法是 ES2022 引入的,这意味着一些老版本的浏览器可能不支持。不过,不用担心,咱们可以用 polyfill 来解决兼容性问题。

polyfill 的实现

if (!Array.prototype.at) {
  Array.prototype.at = function(n) {
    // 将 n 转换为整数
    n = Math.trunc(n) || 0;
    // 处理负数索引
    if (n < 0) {
      n += this.length;
    }
    // 检查索引是否越界
    if (n < 0 || n >= this.length) {
      return undefined;
    }
    // 返回对应索引的元素
    return this[n];
  };
}

if (!String.prototype.at) {
  String.prototype.at = function(n) {
    // 将 n 转换为整数
    n = Math.trunc(n) || 0;
    // 处理负数索引
    if (n < 0) {
      n += this.length;
    }
    // 检查索引是否越界
    if (n < 0 || n >= this.length) {
      return undefined;
    }
    // 返回对应索引的字符
    return this.charAt(n);
  };
}

这段代码首先检查 Array.prototype.atString.prototype.at 是否存在,如果不存在,就自己实现一个。实现逻辑也很简单,就是把负数索引转换成正数索引,然后用 []charAt() 方法访问元素。

注意事项

  • at() 方法接收的参数必须是整数,如果传入小数,会被自动取整。
  • at() 方法不会修改原始数组或字符串。
  • at() 方法的性能和 [] 访问方式差不多,不用担心性能问题。

总结

at() 方法是一个很实用的小工具,可以让你更方便地访问数组和字符串的元素,尤其是从后往前索引的时候。虽然它不是什么神器,但用好了也能提高代码的可读性和简洁性。

练手时间

  1. 写一个函数,接收一个字符串,判断它是否是回文(正着读和倒着读都一样)。用 at() 方法实现。

    function isPalindrome(str) {
      str = str.toLowerCase().replace(/[^a-z0-9]/g, ''); // 移除标点和空格,转换为小写
      for (let i = 0; i < str.length / 2; i++) {
        if (str.at(i) !== str.at(-i - 1)) {
          return false;
        }
      }
      return true;
    }
    
    console.log(isPalindrome('racecar'));   // 输出: true
    console.log(isPalindrome('A man, a plan, a canal: Panama')); // 输出: true
    console.log(isPalindrome('hello'));     // 输出: false
  2. 写一个函数,接收一个数组,返回一个新数组,包含原数组的最后 N 个元素。用 at() 方法实现。

    function getLastNElements(arr, n) {
      if (n > arr.length) {
        return arr.slice(); // 如果 n 大于数组长度,返回整个数组的拷贝
      }
      const result = [];
      for (let i = 0; i < n; i++) {
        result.push(arr.at(-n + i));
      }
      return result;
    }
    
    const numbers = [1, 2, 3, 4, 5];
    console.log(getLastNElements(numbers, 2));  // 输出: [4, 5]
    console.log(getLastNElements(numbers, 3));  // 输出: [3, 4, 5]
    console.log(getLastNElements(numbers, 5));  // 输出: [1, 2, 3, 4, 5]
    console.log(getLastNElements(numbers, 6));  // 输出: [1, 2, 3, 4, 5]

结束语

好了,今天的 at() 方法就讲到这里。希望大家以后在写代码的时候,能想起这个小工具,让你的代码更简洁、更优雅。记住,编程的乐趣在于不断学习和探索,掌握更多的小技巧,才能写出更棒的代码!下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注