Comments 21
Формально — да, баг. Но у себя, например, очень давно не помню, чтобы был где-то нужен перебор кроме как по объектам jQuery — для каких-то подготовительных штук это делает либо шаблонизатор (благо XSLT позволяет избавиться от части велосипедов на клиентской стороне), либо вообще серверная сторона.
Вот единственно верная проверка на Array, у typeof и constructor были какие-то свои минусы. Она же используется в $.isArray в несколько более общем виде:
Проверять результат лучше не на фолс, а на строгое равенство undefined. И если не, то возвращать то что вышло, это покрывает некоторые интересные кейсы типа нахождения первого элемента по какому-то условию.
isArray: function( obj ){
return Object.prototype.toString.call( obj ) === '[object Array]';
}
Проверять результат лучше не на фолс, а на строгое равенство undefined. И если не, то возвращать то что вышло, это покрывает некоторые интересные кейсы типа нахождения первого элемента по какому-то условию.
typeof и constructor не сработают в том случае, если проверяемый объект находится в чужом фрейме, вы правы.
А чем не подходит obj instanceof Array?
Проблема instanceof, как сказали выше в других фреймах, НО:
В виду этих пунктов, я отказался от подобных (isArray, isFunction) функций. Хотя могу где-то ошибаться.
- редкая нужда в дополнительных фреймах (в моей ситуации, разработка хтмл5 приложений)
- если и нужен фрэйм, при его инициализации, передаю нужные объекты в него — получаем работающий instanceof
- скуданя скорость jsperf ( и учитем, что проверок на «Array» бывает много)
В виду этих пунктов, я отказался от подобных (isArray, isFunction) функций. Хотя могу где-то ошибаться.
Способ проверки на массив по косвенным признакам:
isArray: function(value)
{
var __object__ = Object.prototype;
return value && typeof(value) === 'object' && value instanceof Array && !__object__.propertyIsEnumerable.call(value, 'length') && __object__.hasOwnProperty.call(value, 'length');
};
Именно так работает и jQuery.type(obj) === 'array'
В трекер jQuery уже закинули?
Не стоит: 1) это не баг, а возможность использовать интерирование по своим объектам; 2) формальная проверка легче, а значит в данном случае вернее.
И да, Саш, это был бы четвертый дубль — github.com/jquery/jquery/pull/336 %)
Имхо, в доке сказано, что each работает для array-like объектов, а не просто объектов. А вы попытались подсунуть незнамо что с пропертью lenght. Отсюда duck-typing и не сработал.
1) Этот метод не будет работать для коллекций jQuery :) у них свойство constructor = jQuery, соответственно нужно добавить проверку obj.constructor === jQuery.
2) В багтрекере этот баг уже 2 года висит bugs.jquery.com/ticket/7260
2) В багтрекере этот баг уже 2 года висит bugs.jquery.com/ticket/7260
«- Вжжжжжжжж-КРЯК! — сказала японская бензопила.»
Любопытно взглянуть на реализацию из underscore.js. Они несильно ушли от варианта с jQuery, но, во-первых, проверяют тип length (obj.length === +obj.length) а во-вторых, по возможности делегируют вызов нативному forEach, если браузер его поддерживает.
Есть крайне удобная штука — sugarjs.com/api/Array/forEach
Это не баг. Это возможность проходить правильно по любым array-like коллекциям.
Например, по NodeList.
Иначе он будет воспринимать объект как хэш и проходить по остальным методам (у которых enumerable = true), например по length (что совершенно не нужно).
(что касается length, имеются в виду не нативные, а свои коллекции)
Например, по NodeList.
Иначе он будет воспринимать объект как хэш и проходить по остальным методам (у которых enumerable = true), например по length (что совершенно не нужно).
(что касается length, имеются в виду не нативные, а свои коллекции)
1. Давайте рассмотрим ситуацию когда свойство length унаследовано:
Делаем выводы…
2. А теперь о проверке конструктора:
Делаем выводы…
3. Относительно массиво-подобных объектов:
Перед тем как нести чушь, говоря что массиво-подобный объект это любой объект у которого есть свойство length, позволю себе привести пример того как можно создать такой объект:
Вспомним что Function.prototype.apply в ES5 вторым аргументом может принимать массиво-подобный объект, проверим является наш объект таковым:
Чтобы убудиться давайте посотрим на следующие примеры:
4. Как можно проверить является объект массивом:
И по косвенным признакам:
Делаем выводы…
var object = {
};
console.log(object.length) // undefined
object.constructor.prototype.length = 1;
console.log(object.length) // true
delete object.length; // false
console.log(object.length) // 1
Делаем выводы…
2. А теперь о проверке конструктора:
var array = function() {
};
array.prototype.constructor = Array;
var object = new array;
console.log(object.constructor); // Array
console.log(object.length); // undefuned
Делаем выводы…
3. Относительно массиво-подобных объектов:
Перед тем как нести чушь, говоря что массиво-подобный объект это любой объект у которого есть свойство length, позволю себе привести пример того как можно создать такой объект:
var array_like = {
0: 1,
1: 2,
length: 2
};
console.log(array_like.constructor); // Object
Вспомним что Function.prototype.apply в ES5 вторым аргументом может принимать массиво-подобный объект, проверим является наш объект таковым:
console.log(Math.max.apply(null, array_like)); // 2
Чтобы убудиться давайте посотрим на следующие примеры:
void function() {
console.log(Math.max.apply(null, arguments)); // -Infinity
}();
var not_array_like = {
length: 2
};
console.log(Math.max.apply(null, not_array_like)); // NaN
4. Как можно проверить является объект массивом:
var isArray = function (object) {
return Object.prototype.toString.call( object ) === '[object Array]';
};
И по косвенным признакам:
isArray: function(value) {
var __object__ = Object.prototype;
return value && typeof(value) === 'object' && value instanceof Array && !__object__.propertyIsEnumerable.call(value, 'length') && __object__.hasOwnProperty.call(value, 'length');
};
Делаем выводы…
Sign up to leave a comment.
Дифференцирование Object, Array, Number и String