如何移动到数组的上一个/下一个元素 [英] How to move to prev/next element of an array

查看:50
本文介绍了如何移动到数组的上一个/下一个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say we have a list of integers:

var fibonacci = [1,1,2,3,5,8,13,21];

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

I want to be able to get the next and previous element (just to move the element pointer, without modifying the array) in following manner (example, might go without prototype to redefine the Array interface but why not):

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

推荐答案

如果要将列表保留为 Array,则必须更改其 [[prototype]] 使它看起来像一个可迭代的集合:

If you want to keep the list as an Array, you'll have to change its [[prototype]] to make it look like an iterable collection:

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

现在每个 Array 都有方法 prevnext,以及 current 属性,它们指向当前"元素.警告:current 属性可以修改,从而导致不可预测的结果.

Now every Array will have the methods prev and next, and the current property, which points to the "current" elements. A caveat: the current property can be modified, thus leading to impredictable results.

Post scriptum:当索引超出范围时,我不建议让 prevnext 返回 false.如果你真的想,你可以将方法更改为:

Post scriptum: I don't recommend to make prev and next return false when the index is out of range. If you really want to, you can change the methods to something like:

Array.prototype.next = function() {
    if (!((this.current + 1) in this)) return false;
    return this[++this.current];
};

2016 年年中更新

我正在更新这个答案,因为它似乎仍在接收观点和投票.我应该澄清一下,给出的答案是概念证明,总的来说扩展原生类的原型是一种不好的做法,应该在生产项目中避免.

I'm updating this answer because it seems it's still receiving views and votes. I should have clarified that the given answer is a proof of concept and in general extending the prototype of native classes is a bad practice, and should be avoided in production projects.

特别是,它并不多,因为它会与 for...in 循环混淆 - 对于数组应该始终避免这种情况,并且 绝对 对于遍历它们的元素 - 也因为从 IE9 开始,我们可以可靠地执行此操作:

In particular, it's not much because it's going to mess with for...in cycles - which should always be avoided for arrays and it's definitely a bad practice for iterating through their elements - and also because since IE9 we can reliably do this instead:

Object.defineProperty(Array.prototype, "next", {
    value: function() { return this[++this.current]; },
    enumerable: false
});

主要问题是扩展原生类不是面向未来的,也就是说,ECMA 可能会为数组引入一个 next 方法,这些方法可能与你的实施.即使使用非常常见的 JS 框架,它也已经发生了 - 最后一种情况是 MooTools 的 contains 数组扩展 导致 ECMA 将名称更改为 includes(糟糕的举动,IMO,因为我们在 contains="https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList" rel="noreferrer">DOMTokenList 对象,如 Element.classList).

The main problem is that extending native classes is not future-proof, i.e. it may happen that ECMA will introduce a next method for arrays that will probably be incompatible with your implementation. It already happened even with very common JS frameworks - the last case was MooTools' contains array extension which led ECMA to change the name to includes (bad move, IMO, since we already have contains in DOMTokenList objects like Element.classList).

话虽如此,并不是说您必须不扩展原生原型,而是您应该了解自己在做什么.我可以给你的第一个建议是选择不会与未来标准扩展冲突的名称,例如myCompanyNext 而不是 next.这将花费你一些代码优雅,但会让你睡个好觉.

That being said, it's not that you must not extend native prototypes, but you should be aware of what you're doing. The first advice I can give you is to choose names that won't clash with future standard extensions, e.g. myCompanyNext instead of just next. This will cost you some code elegance but will make you sleep sound.

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

Even better, in this case you can effectively extend the Array class:

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 中,扩展原生类更容易:

In ES6, moreover, it's easier to extend native classes:

class MyTraversableArray extends Array {
    next() {
        return this[++this.current];
    }
}

唉,转译器有原生类扩展的困难,Babel 取消了对它的支持.但这是因为它们不能完全复制一些对我们没有影响的行为,所以你可以坚持使用上面的旧 ES3 代码.

Alas, transpilers have a hard time with native class extensions, and Babel removed its support. But it's because they can't exactly replicate some behaviours which have no influence in our case, so you can stick with the above old ES3 code.

这篇关于如何移动到数组的上一个/下一个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆