Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Array each function (https://javascript.ru/forum/misc/18666-array-each-function.html)

melky 10.07.2011 19:12

Array each function
 
требуется быстрая функция для обхода массива, исполняя на каждой итерации функцию. Должна быть возможность прервать цикл.

пока смог реализовать через замыкание.

для чего это мне понадобилось, покажу на абстрактных примерах :)

порядок обхода совершенно безразличен. я могу сделать reverse, если что.
Пример: через замыкание
function each(arr, func) {

var al = arr.length, breaked = false;

do 
    func( arr[al],  al , arr, function(){ breaked=true } );

while (    al-- > 0  &&   breaked==false    ) 

}

var log=[];

each( [1,2,3,"break it",4,5,6,7],    function(a,b,c,d){

                                                         log.push(a);
                                                         a==='break it' && d();
} );

alert( "Прошли : \n\n"+ log.join("\n") )


сильно хочется сделать это через метки, но не могу.

подскажите, пожалуйста, как лучше всего сделать функцию обхода массива с возможностью прерывания

B@rmaley.e><e 10.07.2011 19:28

Цитата:

Сообщение от melky
как лучше всего сделать функцию обхода массива с возможностью прерывания

Взять обычную и выбросить исключение.

melky 10.07.2011 19:44

кажется, сам не стал бы так писать :) да?

Пример: через исключение
var log=[];

try { 
        [1,2,3,"break it",4,5,6,7].forEach ( function(a){ 

                        log.push(a);
                         if(  a==='break it' ) throw "";

                       } );
 } catch (e) {}

alert( "Прошли : \n\n"+ log.join("\n") )

trikadin 10.07.2011 20:05

Я, наверное, что-то не очень понял...

_log=[];
arr=[1, 2, 3, 4, 5, false, 6, 7];
function each(arr, func) {
 for (var i=0; i!= arr.length; ++i) {
  _log.push(arr[i]);
  if(func(arr[i], i, arr)===false) break;
};
};
each(arr, function(a, b, c){if (a===false) return false});
alert(_log);


Нет?

Kolyaj 10.07.2011 20:17

Цитата:

Сообщение от melky
как лучше всего сделать функцию обхода массива с возможностью прерывания

Стандартные some/every.

trikadin 10.07.2011 20:25

И для кроссбраузерности:

Array.prototype.every= Array.prototype.every || function (func, thisObj) {
for (var i=0; i!= this.length; ++i)
 if (i in this && func.call(thisObj, this[i], i, this))
   return false;
 return true;
};


Ну и some так же...

Kolyaj 10.07.2011 20:38

Цитата:

Сообщение от trikadin
if (!Array.every)

Сначала не там ищем метод, потом заменяем существующий на неправильную реализацию.

Aetae 10.07.2011 20:46

Цитата:

Сообщение от Kolyaj (Сообщение 112752)
Сначала не там ищем метод, потом заменяем существующий на неправильную реализацию.

=)
Как это типично...))

trikadin 10.07.2011 20:54

Поправил, виноват...

Kolyaj 10.07.2011 21:00

Ещё нужна проверка i in this, и callback функция не обязана возвращать строго false.

http://alljs.ru/s/files/Array.js

trikadin 10.07.2011 21:11

Цитата:

Сообщение от Kolyaj
Ещё нужна проверка i in this

А зачем? Дурацкий вопрос, наверное... Но всё же?

Kolyaj 10.07.2011 21:29

Элементы в массиве могут быть пропущены.

var a = [1, 2, , , , 3];

trikadin 10.07.2011 21:38

Понял)) Спасибо))

float 11.07.2011 00:46

В моздоках фигурирует такая:
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(searchElement /*, fromIndex */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (len === 0)
      return -1;

    var n = 0;
    if (arguments.length > 0)
    {
      n = Number(arguments[1]);
      if (n !== n) // shortcut for verifying if it's NaN
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }

    if (n >= len)
      return -1;

    var k = n >= 0
          ? n
          : Math.max(len - Math.abs(n), 0);

    for (; k < len; k++)
    {
      if (k in t && t[k] === searchElement)
        return k;
    }
    return -1;
  };
}

Мот кто объяснит зачем монипуляции до цикла?

trikadin 11.07.2011 01:10

Не особо-то она правильная, по-моему... Хотя не мне об этом говорить))

float 11.07.2011 01:18

Вроде в доках заявлена, как эквивалент встроенной.

trikadin 11.07.2011 02:43

Цитата:

Сообщение от float
эквивалент встроенной

Эквивалент встроенной чего? Ты на название посмотри. Мы тут each, вроде как, обсуждали. А потом плавно перешли на every/some.

float 11.07.2011 03:01

Ну я начал копаться в Array.js потом перешёл на доки от мозилы. Там вроде для всех новых методов массива есть эквиваленты. Ну индексоф и попался...

melky 11.07.2011 09:59

Цитата:

Сообщение от melky (Сообщение 112738)
подскажите, пожалуйста, как лучше всего сделать функцию обхода массива с возможностью прерывания

с прерыванием же

видно, не так это просто сделать :)


if( typeof Array.prototype.forEach === 'undefined' ) 

			Array.prototype.forEach = function( func ){
				var arrl, arr = this.reverse();
				
				do if (arrl in arr) 
						func( arr[arrl], arrl, arr );
				while( arrl -= 1 > 0 );
			}
// test ..			
var log=[];

function each( array, func ){
	
	try { array.forEach( func ) } catch(e) {};
	
}
        each( [1,2,3,"break it",4,5,6,7], function(a){ 

                        log.push(a);
                         if(  a==='break it' ) throw "";

                       } );


alert( "Прошли : \n\n"+ log.join("\n") );

Sweet 11.07.2011 10:15

Цитата:

Сообщение от melky
видно, не так это просто сделать

Использую для этого every, и не заметил никаких сложностей.

melky 11.07.2011 10:20

какая разница между forEach и every, например, в моей задаче (прерывание) ?

даже передают обе одинаковые аргументы - член массива, ключ, весь массив

Kolyaj 11.07.2011 11:58

melky,
ещё один неправильно реализующий стандартные функции.

melky 11.07.2011 13:20

if( typeof Array.prototype.forEach === 'undefined' )
   Array.prototype.forEach = function (iterator, context) {
    for (var i = 0, length = this.length >>> 0; i < length; i++) {
      if (i in this) iterator.call(context, this[i], i, this);
    }
  }


Prototype.js

я просто с ума от изящества

но зачем делать так ?
this.length >>> 0

Пример: это же Math.floor
alert ( [ "_______","|examples :","_______", "|9 >>> 0", "=> "+ (9 >>> 0), "| 9.8 >>> 0", "=> "+ (9.8 >>> 0), "_______"].join("\n") );


можно было и так, Kolyaj :)
if( typeof Array.prototype.forEach === 'undefined' )
   Array.prototype.forEach =  function(fn, ctx) {
            for (var i = 0, l = this.length; i < l; i++) 
                       if (i in this)   
                           fn.call(ctx, this[i], i, this);
        };


ну а прерывать как? через метание ?

melky 11.07.2011 13:55

http://jsperf.com/array-each.

Я думаю, nuff said;

всем спасибо.

Kolyaj 11.07.2011 14:09

melky,
а зачем ты мой ник приписал к функции, к которой я не имею никакого отношения?

melky 11.07.2011 14:14

да ладно. какая разница?

Kolyaj 11.07.2011 14:16

Непонятен смысл твоего сравнения. Ты сравниваешь плохую реализацию (throw) с неправильной (i--).

melky 11.07.2011 14:18

это не реализация функции по-умолчанию, а написание своей, с возможностью прервать её, Kolyaj

сколько способов реализации знаю, так и написал :)

tenshi 14.07.2011 13:03

использовать исключения плохо

к тому же, они прерывают только 1 цикл, а сразу два вложенных не умеют. и вообще, использовать исключения в штатной ситуации - надо быть совсем упоротым.

чтобы прерывать нужно передавать функцию прерывания в колбэк. но лучше не использовать для этого замыкания, а сделать итератор

monolithed 14.07.2011 13:21

Цитата:

Сообщение от melky
но зачем делать так ?
this.length >>> 0

во-первых, для инвертирования типа к целочисленному значению (иногда может быть удобней чем унарный +)

alert([typeof '10', typeof ('10' >>> 0)])


во-вторых, для того чтобы предотвратить выход за пределы максимально допустимого диапазона чисел.


Часовой пояс GMT +3, время: 21:07.