Если вы используете Узел 4 или 5, вы можете рассмотреть возможность использования ES6 Symbol.Iterator
. Это самое близкое к PHP ArrayIterator
, о котором я могу думать.
Вот пример сценария использования, которые вы описываете в своем сообщении:
'use strict';
let result = {
items: [
'item1', 'item2', 'item3'
],
[Symbol.iterator](cb) {
let index = 0;
return {
next:() => {
let value = this.items[index];
let done = index >= this.items.length;
// Note that arrow functions won't bind `this.items` to cb's `this`.
if (typeof cb === 'function') {
return cb.call(this.items, value, done, this.items, index++);
} else {
index++;
return { value, done };
}
}
}
}
}
let cb = (value, done, items, index) => {
// Modify original array.
items[index] = items[index] && items[index].toUpperCase();
value = items[index];
return { value, done };
};
let iterator1 = result[Symbol.iterator](cb);
let iterator2 = result[Symbol.iterator]();
console.log(iterator1.next()); // { value: 'ITEM1', done: false }
console.log(iterator2.next()); // { value: 'ITEM1', done: false }
console.log(iterator1.next()); // { value: 'ITEM2', done: false }
console.log(iterator1.next()); // { value: 'ITEM3', done: false }
console.log(result.items); // [ 'ITEM1', 'ITEM2', 'ITEM3' ]
Обратите внимание, что вы можете определить несколько итераторов для перебора одновременно, изменять ссылочный массив, а также добавить свои собственные методы итератора подражать ArrayIterator
, как вам будет угодно.
Я должен также упомянуть, что for-of
конструкция хорошо работает с этим:
'use strict';
let result = {
items: [
'item1', 'item2', 'item3'
]
}
let cb = (value, done, items, index) => {
// Modify original array.
items[index] = items[index] && items[index].toUpperCase();
value = items[index];
return { value, done };
};
let modifiableIterableIterator = {
[Symbol.iterator]() {
let index = 0;
return {
next:() => {
let value = result.items[index];
let done = index >= result.items.length;
// Note that arrow functions won't bind `this.items` to cb's `this`.
if (typeof cb === 'function') {
return cb.call(result.items, value, done, result.items, index++);
} else {
index++;
return { value, done };
}
}
}
}
};
for (let item of modifiableIterableIterator) console.log(item);
modifiableIterableIterator[Symbol.iterator]
такая же, как и предыдущий result[Symbol.iterator]
, за исключением того, что нет более cb
параметра.При передаче итерационного итератора (итеративный итератор - это тот, который определяет метод next
и Symbol.iterator
для объекта), никакие аргументы не передаются Symbol.iterator
, поэтому мы просто делаем обратный вызов явным из метода. Цикл будет выполнять те же операции, что и раньше: заглавные все значения и изменить массив на месте.
Есть некоторые дизайнерские решения о том, как это можно правильно структурировать, но это зависит от вас и способа структурирования вашего приложения.
Так как вы хотите, чтобы поддержать «старый» способ итерации при сохранении такого поведения, только так вы можете сделать это путем перегрузки []
является использование Proxy
объекта ES6 в. Это позволяет выполнять метапрограммирование. К сожалению, внутренней поддержки не хватает, но вы можете использовать прокладки, если вам нужно (я получил эту работу на узле 5 с помощью модуля harmony-reflect
и передал --harmony_proxies
в командной строке).
let proxy = new Proxy(result.items, {
get(target, index) {
target[index] = target[index] && target[index].toUpperCase();
return target[index];
}
});
for (let x = 0; x < result.items.length; x++) console.log(proxy[x]); // 'ITEMx'
console.log(result.items); // [ 'ITEM1', 'ITEM2', 'ITEM3' ]
Объединить имеют новые итераторы и прокси, и у вас есть решение, которое работает с существующей реализации и требованиям завтрашнего дня в вашем коде.
Чтобы сделать работу с кодом, вы просто назначили this.items result.items. Отвечает ли это на ваш вопрос? – aw04
'this.items = result.items;' ...? И зачем создавать объект, который выглядит точно так же, как и объект, с которого вы начинаете? Я думаю, вы слишком задумываетесь об этом. –
Можете ли вы описать, какую проблему вы действительно пытаетесь решить здесь, потому что то, что вы просите, не кажется необходимым или полезным, когда вы можете просто назначить или скопировать массив в любом месте. Не существует общей причины помещать объект-обертку вокруг массива. Это уже полностью функционирующий объект. Теперь, если у вас есть конкретная проблема, которую вы пытаетесь решить, тогда мы могли бы участвовать в лучших способах решения этого вопроса, но вам нужно было бы описать реальную цель. – jfriend00