Законное использование конструктора Array
Мне понравился этот вопрос - Легитимное использование конструктора Function - так что я хотел создать аналогичный вопрос относительно конструктора Array
.
Конечно, литеральная запись массива - это правильный способ создания массивов. Это означало бы, что обозначение new Array
не должно использоваться. И "случай закрыт".
Однако существует одна специфичность формы new Array
. Если передано натуральное число, создается пустой массив и его свойство length
установлено на это число.
Итак,
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
работать правильно?)
Ответы
Ответ 1
Как о альтернативном способе для мелкого клонирования массива?
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
Ответ 2
Я не знаю, учитывается ли это, но в одном случае, когда вы используете конструктор, вам нужно убедиться, что у вас есть чистый, немодифицированный конструктор 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
Довольно многое, что вы можете придумать с помощью функции отображения homebrewn (native .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
, native .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
Из которых эквивалент для циклов довольно ужасен: 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;
}