Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Обсуждений тред (https://javascript.ru/forum/offtopic/47364-obsuzhdenijj-tred.html)

nerv_ 31.03.2015 18:39

Array Like Objects
 
Как правильно и дешево идентифицировать массиво-подообные объекты?
Очевидно, что следующей проверки мало:
var array = [1];
var arrayLike = {0:1, length:1};
var fakeArrayLike = {length:1, height:2};
var window = window;
var fn = function() {};

alert(isArrayLike(array)); // true
alert(isArrayLike(arrayLike)); // true
alert(isArrayLike(fakeArrayLike)); // true | must be false
alert(isArrayLike(window)); // true | must be false
alert(isArrayLike(fn)); // false | must be false
// -------------------

/**
 * @param {*} any
 * @returns {Boolean}
 */
function isArrayLike(any) {
    return isObject(any) && any.hasOwnProperty('length');
}

/**
 * @param {*} any
 * @returns {Boolean}
 */
function isObject(any) {
    return any !== null && typeof any === 'object';
}

Тут написано, что эти объекты должны иметь метод splice, но по факту они его не имеют:
var collection = document.getElementsByTagName('body');
alert(collection.splice);
alert(collection.length);


ангуляр
/**
 * @private
 * @param {*} obj
 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
 *                   String ...)
 */
function isArrayLike(obj) {
  if (obj == null || isWindow(obj)) {
    return false;
  }

  var length = obj.length;

  if (obj.nodeType === 1 && length) {
    return true;
  }

  return isString(obj) || isArray(obj) || length === 0 ||
         typeof length === 'number' && length > 0 && (length - 1) in obj;
}

жуквери
function isArraylike( obj ) {
	var length = obj.length,
		type = jQuery.type( obj );

	if ( type === "function" || jQuery.isWindow( obj ) ) {
		return false;
	}

	if ( obj.nodeType === 1 && length ) {
		return true;
	}

	return type === "array" || length === 0 ||
		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}


Глядя на все это безобразие, кажется, что нет способа точно определить массиво-подобный объект. Так ли это? :)

МаксимкаНевозбанный 31.03.2015 18:54

function likeArray(item) {

  if( !('length' in item) ) return false;

  for(var index = 0; index < item.length; index++){
    if( !(index in item) ) return false;
  }

  return true;
}



:victory: илита

Octane 31.03.2015 19:12

Цитата:

Сообщение от МаксимкаНевозбанный
function likeArray(item) {

  if( !('length' in item) ) return false;

  for(var index = 0; index < item.length; index++){
    if( !(index in item) ) return false;
  }

  return true;
}

илита

значит [1,,2] нифига не похоже на массив, да?

МаксимкаНевозбанный 31.03.2015 19:13

Цитата:

Сообщение от Octane
да?

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

к примеру

arr = [];
arr.length = 100;


тоже не считается массивоподобным я осознанно это сделал хотя мог бы проверять чисто (item.length-1 in item)

Erolast 31.03.2015 19:13

Цитата:

Глядя на все это безобразие, кажется, что нет способа точно определить массиво-подобный объект. Так ли это?
Symbol.iterator in object

?

nerv_ 31.03.2015 19:17

МаксимкаНевозбанный,
Цитата:

Сообщение от nerv_
Как правильно и дешево идентифицировать массиво-подообные объекты?

forEach я и сам могу, но я это делаю уже после идентификации, что более оправданно, нежели для нее
Цитата:

Сообщение от МаксимкаНевозбанный
илита

говоришь :)
var object = {'12.24': 1, foo: NaN, length: 1};
      
alert(likeArray(object));
      
function likeArray(item) {

  if( !('length' in item) ) return false;

  var keys = Object.keys(item);
  var indexCnt = 0;

  for(var i = 0; i < keys.length; i++){
    var key = keys[i]
    if(+key != key) continue;
    indexCnt++
  }

  return indexCnt === item.length;
}

nerv_ 31.03.2015 19:24

Цитата:

Сообщение от Erolast
Symbol.iterator in object

alert(Symbol.iterator in document.getElementsByTagName('body'));
alert(Symbol.iterator in document.querySelectorAll('body'));

Erolast 31.03.2015 19:30

NodeList.prototype[Symbol.iterator] = function*() {
    for (let i = 0; i < this.length; i++) {
        yield this[i];
    }
}

МаксимкаНевозбанный 31.03.2015 19:31

nerv_, я уже изменил свой камент) удаляй свой

МаксимкаНевозбанный 31.03.2015 19:33

function likeArray(item) {
  if( item == null ) return false;
  if( item === window ) return false;
  if( !('length' in item) ) return false;
  if( typeof item === 'function' ) return false;
  if( item.length === 0 ) return true;
  return ( item.length - 1 ) in item
}



вот самый крутой способ и самый быстрый

nerv_ 31.03.2015 19:58

Цитата:

Сообщение от МаксимкаНевозбанный
вот самый крутой способ и самый быстрый

тесты проходит :) (дописал первую строчку)
var array = [1];
var arrayLike = {0:1, length:1};
var fakeArrayLike = {length:1, height:2};
var window = window;
var fn = function() {};
var fake1 = {foo: NaN, length: 1};
var fake2 = {'12.24': 1, length: 1};
var fake3 = '';
var fake4 = '1';

console.log(isArrayLike(document.getElementsByTagName('body')) === true, 1);
console.log(isArrayLike(document.querySelectorAll('body')) === true, 2);
console.log(isArrayLike(array) === true, 3);
console.log(isArrayLike(arrayLike) === true, 4);
console.log(isArrayLike(fakeArrayLike) === false, 5);
console.log(isArrayLike(window) === false, 6);
console.log(isArrayLike(fn) === false, 7);
console.log(isArrayLike(fake1) === false, 8);
console.log(isArrayLike(fake2) === false, 9);
console.log(isArrayLike(fake3) === false, 10);
console.log(isArrayLike(fake4) === false, 11);


function isArrayLike(item) {
  if( typeof item === 'string' ) return false;
  if( item == null ) return false;
  if( item === window ) return false;
  if( !('length' in item) ) return false;
  if( typeof item === 'function' ) return false;
  if( item.length === 0 ) return true;
  return ( item.length - 1 ) in item
}


---

Erolast, не всегда есть возможность патчить)

МаксимкаНевозбанный 31.03.2015 20:02

nerv_, а я вот думал на счет стринга но почему то оставил его, посмотрев на ангуляр, хотя нет в нем смысла

nerv_, ух ты, даже likeArray(document.createTextNode('выыв')) выдает false

поставлю себе в юишку эту функцию ка я)

nerv_ 31.03.2015 20:31

Цитата:

Сообщение от МаксимкаНевозбанный
а я вот думал на счет стринга но почему то оставил его, посмотрев на ангуляр, хотя нет в нем смысла

я пока 50/50 расцениваю. Не определился еще. Хотя, если мы проверяем на "массиво-подобные объекты", строка не объект, т.ч false.

Немного сократил. На последнем тесте врет.
С этими не знаю как правильно.

МаксимкаНевозбанный 31.03.2015 20:46

вообще likeArray предполагается что должна использоваться внутри toArray который по сути строку должен оборачивать в ['строка']

function toArray(item){
  if( likeArray(item) ) return [].slice.call(item);
  return [item]
}


так что строка не должна быть liteArray по уму чтобы можно было делать так


eventNames = toArray(eventsNames)

и если был массив строк то он и останется а если была строка то обернется в массив в котором будет в первой ячейке

kobezzza 31.03.2015 21:36

Цитата:

Сообщение от Zend (Сообщение 364176)
Safort,
Это называется - пилить сук на котором сидишь. Ни разу не видел где бы такой приём понадобился.

Ты просто не сталкивался, но это очень частый кейз.

***

По поводу likeArray, то у меня юзается так:
https://github.com/kobezzza/Collecti.../types.js#L134

Надо пожалуй добавить проверку для window.

nerv_ 31.03.2015 22:31

Цитата:

Сообщение от kobezzza
По поводу likeArray, то у меня юзается так:
https://github.com/kobezzza/Collecti.../types.js#L134

спасибо

Ты в курсе, что все подобные проверки идут лесом ибо
Цитата:

Не друзья: instanceof и фреймы
Оператор instanceof не срабатывает, когда значение приходит из другого окна или фрейма.

Например, массив, который создан в ифрейме и передан родительскому окну — будет массивом в том ифрейме, но не в родительском окне. Проверка instanceof Array в родительском окне вернёт false.

Вообще, у каждого окна и фрейма — своя иерархия объектов и свой window .

Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства [[Class]]. Более подробно это описано в главе Оператор typeof, [[Class]] и утиная типизация.
http://learn.javascript.ru/instanceof

А еще зачем это, если есть старая добрая утиная типизация?) Т.е. эту функцию можно сократить.

Впрочем, это поверхностное суждение, я не знаю как у тебя там все устроено)

kobezzza 31.03.2015 22:43

Цитата:

Ты в курсе, что все подобные проверки идут лесом ибо
Конечно, но видимо просто забыл :) Спасибо, я напишу тесты.

Цитата:

А еще зачем это, если есть старая добрая утиная типизация?) Т.е. эту функцию можно сократить.

Впрочем, это поверхностное суждение, я не знаю как у тебя там все устроено)
Если честно, то я уже не помню, т.к. писал давно, но помню, что так зачем то надо было. Просто со временем всплывают баги - ты их прибиваешь и спокойно забываешь, а потом смотришь и думаешь - нах я это писал ? :D

Я планировал вернуться к разработке новой версии Collection вскорем, проведу ревью кода, но думаю, что здесь так надо было.

trikadin 31.03.2015 23:22

Цитата:

Сообщение от kobezzza
Просто со временем всплывают баги - ты их прибиваешь и спокойно забываешь

Хороший код сам себя комментирует :D

kobezzza 31.03.2015 23:25

Цитата:

Сообщение от trikadin (Сообщение 364299)
Хороший код сам себя комментирует :D

:D

Gozar 01.04.2015 00:12

Цитата:

Сообщение от trikadin
Хороший код

Хороший код, это код с комментариями в узких местах. ;)

Zend 01.04.2015 11:35

Цитата:

Сообщение от kobezzza
Ты просто не сталкивался, но это очень частый кейз.

Можешь пример привести? Расширю хоть своё сознание

kobezzza 01.04.2015 11:49

Цитата:

Сообщение от Zend (Сообщение 364375)
Можешь пример привести? Расширю хоть своё сознание

Легко: у тебя есть очередь, ты пушишь туда таски, потом делаешь apply и один или несколько тасков меняет добавляет / удаляет таски в этой очереди в момент исполнения.

Zend 01.04.2015 12:36

Цитата:

Сообщение от trikadin
Хороший код сам себя комментирует

А как на счёт @param {integer} и т.п. Документатогенераторы ктонибудь юзает ещё? Я дык чёта наигрался уже

kobezzza 01.04.2015 13:04

Цитата:

Сообщение от Zend (Сообщение 364397)
А как на счёт @param {integer} и т.п. Документатогенераторы ктонибудь юзает ещё? Я дык чёта наигрался уже

Не путай аннотации с комментами. Аннотации нужно писать в любом случае.

trikadin 01.04.2015 13:14

Цитата:

Сообщение от Zend
Документатогенераторы ктонибудь юзает ещё?

Я для ide пользуюсь аннотациями))

l-liava-l 01.04.2015 14:56

Ребят, годную книгу по паттернам архитектурного проганья не подскажете?
На какой digest свежечка стоит обратить внимание?

А то я выпал на 3 месяца из жизни :)

Спасибо.

Safort 01.04.2015 15:16

l-liava-l,
это подойдёт? http://largescalejs.ru/

kobezzza 01.04.2015 15:52

Цитата:

Сообщение от Safort (Сообщение 364451)
l-liava-l,
это подойдёт? http://largescalejs.ru/

Какой то устаревший справочник. Лучше уж тогда просто Стефана Стоянова прочитать или Банду четырех.

Safort 01.04.2015 18:15

kobezzza,
так "Банда четырёх" ещё старее, не?)

kobezzza 01.04.2015 18:48

Цитата:

Сообщение от Safort (Сообщение 364486)
kobezzza,
так "Банда четырёх" ещё старее, не?)

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

Хотя есть Head First Паттерны проектирования по новее.

l-liava-l 01.04.2015 18:52

Цитата:

l-liava-l,
это подойдёт? http://largescalejs.ru/
На бутерброд похоже, прочитал пару топиков, знаком.

Цитата:

Стефана Стоянова
Было.

Цитата:

Банду четырех.
Небыло. Стоит ли?

trikadin 04.04.2015 22:13

Слушайте, а кто может мне объяснить, чем опасно для кросдоменной политики применение атрибута download? Вот что я имею в виду:

<a href="https://pp.vk.me/c411223/v411223005/2575/Cr9yOId2NPc.jpg" download="wow-pic.jpg">Картинка сохранится под оригинальным именем</a>


Зачем это?

Octane 04.04.2015 22:20

Chrome не отправляет referrer, когда происходит клик по <a download>, поэтому для ограничения доступа к ресурсам со сторонних сайтов придется выдумать что-то еще, кроме проверки referrer.

trikadin 04.04.2015 22:25

Octane, так ограничения доступа же не происходит. И он начинает скачку, всё в порядке. Просто имя из атрибута download он не берёт.

Safort 07.04.2015 08:38

Как считаете, что релизнется раньше - Халфа 3 или новая версия учебника javascript.ru?)

kobezzza 07.04.2015 10:12

Цитата:

Сообщение от Safort (Сообщение 365356)
Как считаете, что релизнется раньше - Халфа 3 или новая версия учебника javascript.ru?)

FF 60 на Servo :D

Safort 07.04.2015 10:24

kobezzza,
лол:D

trikadin 07.04.2015 12:59

Чет я сомневаюсь.
http://habrahabr.ru/post/255103/

nerv_ 07.04.2015 13:53

Цитата:

Сообщение от trikadin
Чет я сомневаюсь.
http://habrahabr.ru/post/255103/

только что читал :)

К 2025 году чтобы все писали на языке программирования 1С:Предприятие

Gozar 07.04.2015 14:45

Цитата:

Сообщение от trikadin
Чет я сомневаюсь.

Не сцы, Яндекс.браузер, Мейл.браузер уже созданы в секретных лабораториях страны. Такими темпами, уже через каких-нибудь пару месяцев страна перевыполнит 10 летний план.

http://bolgenos.ru/ Новейшая операционная система, разработанная талантливым программистом страны.

Через 2 месяца он допишет всё необходимое ПО страны!


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