LINUX.ORG.RU

JavaScript. Проверка типов элементов массивов.

 , , , ,


1

1

Хочу, чтобы в юнит-тестах проверялся тип возвращаемого в callback-е значения: array of string.

В статике (Pascal, C#, Ява) это делает компилятор, а в динамике - это же обязаны делать юнит-тесты, так ведь?

Использую chai.js, типа стандарт де-факто. Сам он не умеет это делать. ОК, есть плугин chai-things.

Пишу:

var list = ['1', '2']

should.exist(list) // Passed

list.should.be.an('array') // Passed
     .with.length(2) // Passed
     .and.all.be.an('string') // Failed: expected '1' to be a string

Т.е. эта редиска не умеет проверять тип элементов массивом. Написал в баг-трекер проекта, жду, что ответит аффтар.

JavaScript 1995-2015. 20 лет на рынке наступания на грабли.

Зы. Теперь я понимаю, почему TJ ушел на Go.

Зы. зы. Интерсно, через сколько месяцев они все таки реализуют сабж.



Последнее исправление: EnterpriseMobility (всего исправлений: 1)

Ответ на: комментарий от EnterpriseMobility

твоя позабористей будет. стрелки рулез.

anonymous
()
Ответ на: комментарий от EnterpriseMobility

Стрелочки вместо функций играют эстетическую роль (что объясняет количество кофескрипт-хипстеров)

Более того. Символ => больше похож на оператор сравнения. выделенное редактором слово function воспринимается лучше

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Лексическое связывание. Значения специальных переменных this, super и arguments определяются не тем, как стрелочные функции были вызваны, а тем, как они были созданы. Неизменяемые this, super и arguments. Значения этих переменных внутри стрелочных функций остаются неизменными на протяжении всего жизненного цикла функции. Стрелочные функции не могут быть использованы как конструктор и кидают ошибку при использовании с оператором new. Недоступность «собственного» значения переменной arguments.

http://habrahabr.ru/company/mailru/blog/213455/

В переводе на русский это означает, что всю выразительную силу js сливаем в унитаз, превращая его в некое подобие быдлоязычка вроде пистона. Я надеюсь, что они старые хоть оставят.

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

Почитал статью. Поведение у ожидаемое от стрелочки. Если она еще и привязывется к объекту вместо прототипа - было бы вообще прекрасно. А если к прототипу - то такой же отстой, что и function

function View(){ this.msg = "Message from View" }
View.prototype.click() => { alert(this.msg) }

inherit(MyView, View); function MyView($el){
  View.call(this);
  this.msg = "Message from MyView";
  $el.addEventListener("click", this.click) //Должен алертнуть "Message from MyView"
}

var myView = new MyView(document.getElementById("MyYoba"))
makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Поведение у ожидаемое от стрелочки

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

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

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

makoven ★★★★★
()
Ответ на: комментарий от makoven

Если она еще и привязывется к объекту вместо прототипа - было бы вообще прекрасно. А если к прототипу - то такой же отстой, что и function

Это, кстати, вообще феерический бред какой-то. Что значит вместо прототипа? Прототип, это объект, а не функция. Ты о JS, я смотрю, вообще весьма слабое представление имеешь.

jackdempsey2015
()
Ответ на: комментарий от makoven
function View(){ this.msg = "Message from View" }
View.prototype.click() => { alert(this.msg) }

Кстати, я не совсем понял, что ты хотел сказать своим примером, но то что ты показал — это так как работают обычные функции. Экземпляр View будет иметь метод click, который будет связываться со значением «Message from View»

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

Я же привел пример. Надо было написать там class-сахарок вместо prototype. Суть в чем: описываешь es6-класс, описываешь его методы. А потом передаешь эти методы прямо в addEventListener. Безо всяких var that=this или method.bind(this). Вот это было бы удобно и энтерпрайзненько

makoven ★★★★★
()
Ответ на: комментарий от makoven

Безо всяких var that=this или method.bind(this)

тебе что, 2 слова лень написать? Я же тебе говорю, что обратной стороной монеты тут будет то, что ты сломаешь нормальное ООП.


Person=function(name){this.name=name}
Person.prototype.say=function(){console.log(this.name)}

jack=new Person("Jack")
john=new Person("John")

jack.say()
john.say()




//>>>> Jack
//>>>> John
Откуда функция say узнает имя объекта, если у нее будет лексическое связывание?

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

Откуда функция say узнает имя объекта, если у нее будет лексическое связывание?

Как я уже говорил, пока не могу ответить тебе на этот вопрос. Ибо не имел дело со стрелочками.

тебе что, 2 слова лень написать?

Ты видимо мало пользуешься событиями и прочей асинхронщиной в совокупности с объектами. Всюду таскать этот нещастный this - та еще заноза в заднице

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 2)
Ответ на: комментарий от makoven

Всюду таскать этот нещастный this - та еще заноза в заднице

А почему нельзя для твоих «суперсложных» кейзов использовать лексический скоп напрямую? eg:

 
MyView=function(message){
 this.click=function(){alert(message)}
}
MyView.prototype.addListenerTo=function(el){el.addEventListener("click", this.click)}

myView=new MyView("message from view")
myView.addListenerTo(element)
 

jackdempsey2015
()
Ответ на: комментарий от makoven

На самом деле в JS все с точностью до наоборот, в плане удобства, там слишком много статики. В Ъ динамике все эти ваши форичи пишуться гораздо проще


list map(+ 1) reduce(+) * 2

Типо того. Именно благодаря динамике. Хашкелисты нервно курят в сторонке

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

Ну вообще-то так и должно быть. Например метод render у вьюхи может использоваться в разных местах. То же самое с методом click. Сейчас использую вот такой костыль

  Event.prototype.bindListeners = function(names){
    names.forEach(function(name){
      var listener = "_" + name;
      if(!this[listener])
        throw Error("Can't bind missing listener '" + listener + "'");
      this[name] = this[listener].bind(this);
    }, this);
  };

На прототипе вьюхи создаю методы _click, _render, _change, etc. В конструкторе делаю this.bindListeners([«click», «render», «change»])

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от jackdempsey2015

Есть livescript специально для любителей подобного невнятного криптопоноса

makoven ★★★★★
()
Ответ на: комментарий от makoven

Слушай, это какая-то херня. Ты тут мало того, что биндишь их тут, ты еще копируешь их из цепочки прототипов. То есть, если в родителях определены эти методы, они тупо скопируются в текущий объект, для которого вызван bindListeners. Это уродство ничего кроме путаницы не принесет.

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

jackdempsey2015
()
Ответ на: комментарий от makoven

И возникает вопрос, опять же, нахрен тебе это чрезжопное копирование, если точно так же их все можно сразу инициализировать при создании экземпляра. Даже с байндом, все равно проще

Event=function(){
  this.foo=function(){...}.bind(this)
  this.bar=function(){...}.bind(this)
}
будет то же самое, что у тебя, только проще.

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

Ну я не знаю других способов намертво связать метод с объектом. Чтобы потом можно было спокойно пихать его в addEventListener, forEach, итд. Подскажешь другой способ - буду благодарен

makoven ★★★★★
()
Ответ на: комментарий от jackdempsey2015

Во-первых, будет помойка. Пихать описание методов в конструктор - моветон. Во-вторых, при создании тысячи объектов, будут созданы тысячи методов. А в моем костыле методы создаются единожды в прототипе, а в экземплярах создаются ссылки на эти методы через нативный bind(this). Что, мне кажется, должно быть лучше по производительности

makoven ★★★★★
()
Ответ на: комментарий от makoven

а в экземплярах создаются ссылки на эти методы через нативный bind(this). Что, мне кажется, должно быть лучше по производительности

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

jackdempsey2015
()
Ответ на: комментарий от makoven

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

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

bind создает копию функции

Тут всё на совести оптимизатора конкретного js-движка. Функция-то нативная. А в твоем случае ничего не заоптимизируешь

makoven ★★★★★
()
Ответ на: комментарий от jackdempsey2015

Я не вижу тут ничего про копирование

15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]]) # Ⓣ Ⓡ Ⓓ
The bind method takes one or more arguments, thisArg and (optionally) arg1, arg2, etc, and returns a new function object by performing the following steps:

Let Target be the this value.
If IsCallable(Target) is false, throw a TypeError exception.
Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
Let F be a new native ECMAScript object .
Set all the internal methods, except for [[Get]], of F as specified in 8.12.
Set the [[Get]] internal property of F as specified in 15.3.5.4.
Set the [[TargetFunction]] internal property of F to Target.
Set the [[BoundThis]] internal property of F to the value of thisArg.
Set the [[BoundArgs]] internal property of F to A.
Set the [[Class]] internal property of F to «Function».
Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in 15.3.3.1.
Set the [[Call]] internal property of F as described in 15.3.4.5.1.
Set the [[Construct]] internal property of F as described in 15.3.4.5.2.
Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3.
If the [[Class]] internal property of Target is «Function», then
Let L be the length property of Target minus the length of A.
Set the length own property of F to either 0 or L, whichever is larger.
Else set the length own property of F to 0.
Set the attributes of the length own property of F to the values specified in 15.3.5.1.
Set the [[Extensible]] internal property of F to true.
Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
Call the [[DefineOwnProperty]] internal method of F with arguments «caller», PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
Call the [[DefineOwnProperty]] internal method of F with arguments «arguments», PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
Return F.
The length property of the bind method is 1.
makoven ★★★★★
()
Ответ на: комментарий от jackdempsey2015

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

makoven ★★★★★
()
Ответ на: комментарий от makoven

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

jackdempsey2015
()
Ответ на: комментарий от jackdempsey2015

Ты считаешь себя умнее, чем есть на самом деле

makoven ★★★★★
()
10 сентября 2015 г.
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.