Законное использование конструктора Array - PullRequest
13 голосов
/ 10 декабря 2011

Мне понравился этот вопрос - Законное использование конструктора Function - поэтому я хотел создать аналогичный вопрос в отношении конструктора Array.

Конечно, буквенная нотация массива является правильным способом создания массивов. Это будет означать, что запись new Array не должна использоваться. И «дело закрыто».

Однако есть одна особенность формы new Array. Если передается натуральное число, создается пустой массив, и его свойство length устанавливается на это число.

So

arr = new Array( 7 );

эквивалентно

arr = [];
arr.length = 7;

Это можно считать особенностью. Мне было интересно, если эта «функция» имеет реальное использование. Недавно я наткнулся на одно такое (простое) использование:

new Array( n + 1 ).join( '*' ) // returns string containing n stars

// e.g.
new Array( 3 ).join( '*' ) // returns '**'
new Array( 6 ).join( '*' ) // returns '*****'

Это круто, но надеялся на более продвинутые варианты использования. (Что-то, что сделало бы запись new Array легитимным инструментом в программах JavaScript.)


Обновление: Я заметил, что библиотека jQuery использует нотацию new Array( len ) в одном экземпляре - она ​​находится внутри функции when (поиск "when:"):

when: function( firstParam ) {
    var args = sliceDeferred.call( arguments, 0 ),
        i = 0,
        length = args.length,
        pValues = new Array( length ),
        count = length,
        pCount = length,
        // etc.

Они используют его для инициализации локальной переменной pValues, которая используется в локальной функции ниже в коде:

function progressFunc( i ) {
    return function( value ) {
        pValues[ i ] = arguments.length > 1 ?
                sliceDeferred.call( arguments, 0 ) : value;
        deferred.notifyWith( promise, pValues );
    };
}

Я бы хотел знать, если изменить назначение на

pValues = [],

сломает программу ... (Требуется ли new Array( length ) для правильной работы notifyWith?)

Ответы [ 3 ]

3 голосов
/ 10 декабря 2011

Я не знаю, считается ли это, но один из случаев, когда вы бы использовали конструктор, это если вам нужно быть уверенным, что у вас чистый, неизмененный конструктор Array.Вы можете создать «песочницу iframe»

var iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
var Safe = frames[frames.length - 1];

, а затем создать подобные массивы ...

var things = new Safe.Array('x', 'y', 'z');

... зная, что в ваших массивах не будет посторонних предметов впрототип, помещенный туда другими сценариями.

Однако, эта функция не использует функцию «один параметр в виде длины массива».Единственная вещь, которая, вероятно, действительно хороша - это создание огромных массивов для тестирования производительности.

3 голосов
/ 10 декабря 2011

Практически все, что вы можете придумать с помощью доморощенной функции карты (нативная .map не повторяется, а jQuery.map - просто полные ошибки)

Создание диапазонов:

//1-20

map( Array( 20 ), function( v,i ){
return i+1;
});
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]


//-50 - 0

map( Array( 51 ), function( v,i ){
return i-50;
});

//[-50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0]

В общем, вместо того, чтобы делать:

var a = [],
    l = 10;

    while ( l-- ) {
        a.unshift( 
            (function(l){
            return function() {
                alert( l );
            };
            })( l )
        );
    }

Вы можете сделать это:

var a = map( Array( 10 ), function ( v, i ) {
    return function(){
        alert( i );
    };
});

Обратите внимание, что это относится только к jQuery.map или shimmed .map, родной .mapне выполняет итерации массива.

Если вы не используете jQuery (который сглаживает результат :(), вы можете создать трехмерные массивы следующим образом:

var xyz = map(Array(10), function (v, i) {
    return map(Array(10), function (v, j) {
        return map(Array(10), function (v, k) {
            return i * 100 + j * 10 + k;
        });
    });
});

xyz[0][0][0] // 0

xyz[9][9][9] // 999

xyz[4][4][4] // 444

xyz[3][5][8] // 358

Из которых эквивалентЦиклы for довольно ужасны: P

Быстрая реализация функции карты для полноты:

function map( elems, callback ){
var i, length = elems.length, ret = [];
    for ( i = 0; i < length; i++ ) {
        value = callback( elems[ i ], i );
        ret[ ret.length ] = value;  
    }
return ret;
}
3 голосов
/ 10 декабря 2011

Как насчет альтернативного способа поверхностного клонирования массива?

var arr = [1,2,3];

var arr2 = Array.apply( null, arr );

arr === arr2; // false;

arr.length === arr2.length; // true

Да, я достигаю здесь, потому что вы просто используете .slice(), но тогда я действительно не вижу использованияArray в первую очередь нелегитимно, если вы знаете, что делаете.


Не по теме, но один из способов сделать общую функцию, использующую Array или slice.Требуется bind. Сейчас слишком лениво, чтобы обновляться для старых браузеров.

http://jsfiddle.net/fdgBU/1/

var slicer,
    apply = Function.prototype.apply;

if( apply.bind ) {
    try {
        (slicer = apply.bind( Array, null ))({length:0});
    } catch( e ) {
        slicer = apply.bind([].slice);
    }
} else {
   slicer = function( coll ) {
        if( !coll || coll.length !== +coll.length ) return;
        var res = [], i = 0, len = coll.length >>> 0;
        for( ; i < len; ++i ) {
            res[i] = coll[i];
        }
        return res;
    };
}

var arr_like = {'0':true,'1':true,'2':true,length:3},
    arr = slicer( arr_like );

console.log( arr ); // [true, true, true]

console.log( arr.length === arr_like.length); // true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...