Comments 30
Вряд ли это решение подойдёт для давно разрабатываемого проекта или для разработки в команде, где пишут только на чистом JS. А это не такой уж вырожденный случай, я вот так и работаю, например, как и многие фрондендеры в крупных компаниях.
Аннотации вам в любом случае писать придётся в документации. Так что лучше уж сразу писать формальные аннотации, по которым можно и документацию генерировать, чем лениться аннотировать код, а потом лениться обновлять документацию.
С одной стороны, несовпадение типов аргументов — это очень маленький процент от всех ошибок типизации. Например, если нужно отправить массив строк через POST и в него случайно попадет функция, мы об этом не узнаем.
С другой стороны, есть подозрение что он может сломать работающий код:
function hasDuplicates(arr) {
for(var i = 0; var i < arr.length - 1; i++) {
for(var j = i + 1; j < arr.length; j++) {
if(arr[i] === arr[j]) return true;
}
}
return false;
}
var result = hasDuplicates(['a', true]); // выкинет ошибку?
Сломать он ничего не сможет, потому что всего лишь выводит предупреждения в консоль, сохраняя результат операции.
Для вашего примера — да, будет ворнинг, т. к. в одном массиве хранятся данные разных типов (что не есть хорошо):

===
специально сделан для того, чтобы безопасно сравнивать объекты потенциально разных типов. Если есть гарантия, что сравниваемые объекты всегда одного типа — можно и ==
использовать.Если вы действительно проверяете с помощью простого
typeof
, как в примере, то у вас наверняка выдается ошибка при сравнении с null
или undefined
— хотя такое сравнение вполне корректно.Кстати говоря, массив из элементов разных типов — это нормальная практика в JS-библиотеках. Например, в Angular так указываются аннотации для Dependency Injection.
Если есть гарантия, что сравниваемые объекты всегда одного типа — можно и == использовать.
С точки зрения синтаксиса да, но с точки зрение надежности, я бы не рекомендовал использовать "==".
Если вы действительно проверяете с помощью простого typeof, как в примере, то у вас наверняка выдается ошибка при сравнении с null или undefined — хотя такое сравнение вполне корректно.
Про явное сравнение x === null
и x === undefined
абсолютно согласен, в таких случаях разработчик явно показывает, что ожидает в переменной null|udnefined
, поэтому предупреждений не будет.
Можно побыть немного занудой? Если в массиве будет NaN, ваш код сам сломается. Лучше так:
function hasDuplicates(arr) {
for(var i = 0; i < arr.length - 1; i++) {
if(arr.includes(arr[i], i + 1)) return true;
}
return false;
}
var result = hasDuplicates([NaN, 'a', true, NaN]); // ваша версия вернет false, моя - true
Есть еще подобный плагин для проверки в рантайме, но для Flow: babel-plugin-tcomb. Сам tcomb тоже стоит внимания.
Про производительность хотел бы посмотреть тесты и методику их постановки. Не то чтобы я не мог их поставить сам, но я не думаю что мне это нужно, всё и так понятно, не бывает бесплатного исполнения дополнительного кода.
Ну какой удар по производительности? Не будите же вы это в продакшене использовать. Это для этапа разработки.
Да, именно.
Кстати по сравнению с тем, что происходит например при транспайлинге es6 --> es5, то тут оверхед совсем небольшой: мы же и так в коде иногда пишем явную проверку через typeof
в условиях.
что происходит например при транспайлинге es6 --> es5
а что там происходит? Можно конкретные примеры? Опять же с замерами если можно.
Пример можно взять прямо из REPL на сайте бабеля: https://babeljs.io/repl/
Было:
class A extends B {}
Стало:
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var A = function (_B) {
_inherits(A, _B);
function A() {
_classCallCheck(this, A);
return _possibleConstructorReturn(this, (A.__proto__ || Object.getPrototypeOf(A)).apply(this, arguments));
}
return A;
}(B);
Да: https://jsperf.com/runtyper-equal-perf
Сравним насколько медленнее становится ===
если заменить его на ==
и на самовызывающийся strictEqual(x, y)
с проверкой типов:
Chrome 57:
== — 67% slower
strictEqual() — 94% slower
YaBrowser 17.3:
== — 84% slower
strictEqual() — 94% slower
Firefox 52:
== — 99% slower
strictEqual() — same time(!)
ок, посмотрю.
Да, полезный доклад.
Хотя в данном случае после заворачивания в функции получились ровно такие же результаты.
Runtyper — инструмент для проверки типов при выполнении JavaScript кода