首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何移动到数组的上一个/下一个元素

如何移动到数组的上一个/下一个元素
EN

Stack Overflow用户
提问于 2012-09-12 22:36:02
回答 5查看 82.9K关注 0票数 21

假设我们有一个整数列表:

代码语言:javascript
运行
复制
var fibonacci = [1,1,2,3,5,8,13,21];

我希望能够以以下方式获取下一个和前一个元素(只是移动元素指针,而不修改数组)(例如,可以不使用prototype来重新定义Array接口,但为什么不可以):

代码语言:javascript
运行
复制
fibonacci.prev(); // returns false
fibonacci.next(); // returns 1
fibonacci.next(); // returns 1
fibonacci.next(); // returns 2
fibonacci.next(); // returns 3
fibonacci.next(); // returns 5
fibonacci.next(); // returns 8

fibonacci.prev(); // returns 5

fibonacci.next(); // returns 8
fibonacci.next(); // returns 13
fibonacci.next(); // returns false
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-09-12 22:39:27

如果你想保持列表作为一个Array,你必须改变它的[[prototype]],使它看起来像一个可迭代的集合:

代码语言:javascript
运行
复制
Array.prototype.next = function() {
    return this[++this.current];
};
Array.prototype.prev = function() {
    return this[--this.current];
};
Array.prototype.current = 0;

现在,每个Array都将拥有方法prevnext,以及指向“当前”元素的current属性。注意:可以修改current属性,从而导致不可预知的结果。

后脚本:我不建议在索引超出范围时让prevnext返回false。如果您真的想这样做,您可以将方法更改为如下所示:

代码语言:javascript
运行
复制
Array.prototype.next = function() {
    if (!((this.current + 1) in this)) return false;
    return this[++this.current];
};

2016年中更新

我正在更新这个答案,因为它似乎仍然收到了意见和投票。我应该澄清的是,给出的答案是概念的证明,一般来说,扩展本机类的原型是一种糟糕的做法,应该在生产项目中避免。

特别是,它不是很多,因为它会扰乱for...in周期-对于数组来说,这应该总是避免的,而且对于迭代它们的元素来说,这绝对是一个糟糕的做法-还因为自从IE9以来,我们可以可靠地这样做:

代码语言:javascript
运行
复制
Object.defineProperty(Array.prototype, "next", {
    value: function() { return this[++this.current]; },
    enumerable: false
});

主要的问题是,扩展本机类不是面向未来的,也就是说,ECMA可能会为数组引入一个next方法,这可能会与您的实现不兼容。即使是在非常常见的JS框架中,这种情况也已经发生了--最后一个例子是MooTools' contains array extension,它导致了ECMA to change the name to includes (糟糕的举动,因为我们已经在像Element.classList这样的DOMTokenList对象中使用了contains )。

话虽如此,这并不是说你不能扩展原生原型,但你应该意识到你在做什么。我能给你的第一个建议是选择不会与未来的标准扩展冲突的名称,例如myCompanyNext而不只是next。这会让你失去一些代码的优雅,但会让你睡得很香。

更好的是,在这种情况下,您可以有效地扩展Array类:

代码语言:javascript
运行
复制
function MyTraversableArray() {
    if (typeof arguments[0] === "number")
        this.length = arguments[0];
    else this.push.apply(this, arguments);

    this.current = 0;
}
MyTraversableArray.prototype = [];
MyTraversableArray.prototype.constructor = MyTraversableArray;
MyTraversableArray.prototype.next = function() {
    return this[++this.current];
};
MyTraversableArray.prototype.prev = function() {
    return this[--this.current];
};

此外,在ES6中,扩展本机类更容易:

代码语言:javascript
运行
复制
class MyTraversableArray extends Array {
    next() {
        return this[++this.current];
    }
}

遗憾的是,转译器有a hard time with native class extensions,而Babel删除了它的支持。但这是因为它们不能精确地复制一些在我们的情况下没有影响的行为,所以你可以坚持使用上面的旧ES3代码。

票数 39
EN

Stack Overflow用户

发布于 2012-09-12 23:16:59

我通常建议不要向Array.prototype添加东西,因为外面有很多非常糟糕的JavaScript。例如,如果您设置了Array.protoype.next = function () {},而某人具有以下代码,那么就会出现问题:

代码语言:javascript
运行
复制
var total = 0, i, myArr = [0,1,2];
for(i in myArr) {
    total += myArr[i];
}
total; //is probably "3next"

这种对for-in循环的不良使用是令人不安的。因此,您添加到Array的原型中是自找麻烦。然而,构建一个包装器来完成您想要做的事情是相当容易的:

代码语言:javascript
运行
复制
var iterifyArr = function (arr) {
    var cur = 0;
    arr.next = (function () { return (++cur >= this.length) ? false : this[cur]; });
    arr.prev = (function () { return (--cur < 0) ? false : this[cur]; });
    return arr;
};

var fibonacci = [1, 1, 2, 3, 5, 8, 13];
iterifyArr(fibonacci);

fibonacci.prev(); // returns false
fibonacci.next(); // returns 1
fibonacci.next(); // returns 1
fibonacci.next(); // returns 2
fibonacci.next(); // returns 3
fibonacci.next(); // returns 5
fibonacci.next(); // returns 8
fibonacci.prev(); // returns 5
fibonacci.next(); // returns 8
fibonacci.next(); // returns 13
fibonacci.next(); // returns false

以下是一些注意事项:

首先,如果超过end,您可能希望让它返回undefined而不是false。其次,因为此方法使用闭包隐藏了cur,所以您无法在数组上访问它。因此,您可能希望使用cur()方法来获取当前值:

代码语言:javascript
运行
复制
//Inside the iterifyArr function:
    //...
    arr.cur = (function () { return this[cur]; });
    //...

最后,您的需求并不清楚“指针”在多大程度上保持在结束之后。以下面的代码为例(假设fibonacci设置如上):

代码语言:javascript
运行
复制
fibonacci.prev(); //false
fibonacci.prev(); //false
fibonacci.next(); //Should this be false or 1?

在我的代码中,它应该是false,但您可能希望它是1,在这种情况下,您必须对我的代码进行几个简单的更改。

哦,因为函数返回arr,所以您可以在定义数组的同一行上“迭代”它,如下所示:

代码语言:javascript
运行
复制
var fibonacci = iterifyArr([1, 1, 2, 3, 5, 8, 13]);

这可能会让你的事情变得更干净。您还可以通过在数组上重新调用iterifyArr来重置迭代器,或者可以编写一个方法来轻松地重置迭代器(只需将cur设置为0)。

票数 23
EN

Stack Overflow用户

发布于 2018-01-22 17:23:40

这方面的next方面现在被构建到数组中,因为从ES2015开始,数组是可迭代的,这意味着您可以为它们获得一个具有next方法的迭代器(但请继续阅读"prev“部分):

代码语言:javascript
运行
复制
const a = [1, 2, 3, 4, 5];
const iter = a[Symbol.iterator]();
let result;
while (!(result = iter.next()).done) {
  console.log(result.value);
}

迭代器只能前进,不能双向前进。当然,您通常不会显式地使用迭代器,而是将其用作某些迭代构造的一部分,比如for-of

代码语言:javascript
运行
复制
const a = [1, 2, 3, 4, 5];
for (const value of a) {
  console.log(value);
}

您可以很容易地为自己提供一个双向迭代器:

创建一个接受数组并返回迭代器的独立函数,或者创建一个接受数组并返回迭代器的独立函数,或者创建一个子类Array并覆盖子类中的迭代器的

  • ,或者使用您自己的迭代器替换默认的Array迭代器(只需确保它的工作方式与默认的完全一样!)

G215>

下面是一个带有子类的示例:

代码语言:javascript
运行
复制
class MyArray extends Array {
  // Define the iterator function for this class
  [Symbol.iterator]() {
    // `index` points at the next value we'll return
    let index = 0;
    // Return the iterator
    return {
      // `next` returns the next
      next: () => {
        const done = index >= this.length;
        const value = done ? undefined : this[index++];
        return { value, done };
      },
      // `prev` returns the previous
      prev: () => {
        const done = index == 0;
        const value = done ? undefined : this[--index];
        return { value, done };
      }
    };
  }
}

// Demonstrate usage:
const a = new MyArray("a", "b");
const i = a[Symbol.iterator]();
console.log("next", JSON.stringify(i.next()));
console.log("next", JSON.stringify(i.next()));
console.log("next", JSON.stringify(i.next()));
console.log("prev", JSON.stringify(i.prev()));
console.log("prev", JSON.stringify(i.prev()));
console.log("prev", JSON.stringify(i.prev()));
console.log("next", JSON.stringify(i.next()));
代码语言:javascript
运行
复制
.as-console-wrapper {
  max-height: 100% !important;
}

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12390626

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档