Comments 53
Сейчас это очень даже выразительный и понятный язык.
Довольно старая статья об этом: When is it OK to use == in JavaScript?.
По большому счету есть кейсы когда можно, но нет кейсов — когда нужно )
В библиотеках часто используют "когда можно", чтобы код сократить (личное наблюдение).
function ping(host, count) {
count = count || 5;
/* ... */
}
как раз и были созданы параметры по умолчанию, упоминаемые выше. Вот как бы оно выглядело после рефакторинга:
function ping(host, count = 5) {
// count = count || 5;
/* ... */
}
Поэтому приведенный автором способ улучшения
function ping(host, count) {
// OR arguments.length?
if (typeof count == 'undefined') {
count = 5;
}
/* ... */
}
ничем не лучше антипаттерна
count = count || 5;
1. Верный вариант задать аргумент по умолчанию — это default parameters.
2. Если все таки нужно определить переменную по месту, то лучше не использовать «логический» оператор с проверкой наличия чего-либо.
3. Если в проверку еще добавляется валидация в несколько условий, то нормальный if statement еще более необходим. Хотелось бы верить, что это понятно (как было прокомментировано выше), но код с инициализацией переменной через кучу И и ИЛИ с проверками встречается.
let timestamp = +new Date;
Но ведь есть у Date известный метод getTime, давайте использовать его:
let timestamp = (new Date()).getTime();
Вообще то, правильно будет
let timestamp = Date.now();
let str = ''+(expr);
let str = String(expr);
Результат — такой же, только понятен всем.
строго говоря, не такой же. Если expr — это объект, у которого есть метод valueOf, то первый способ переведет в строку то, что вернул метод valueOf, а второй — то, что вернул метод toString.
let d = new Date;
''+d; // Wed Dec 12 2018 14:47:27 GMT+0300
+d; // 1544615247741
Здесь будет строковое преобразование, так как один из операндов — явно строка. Но замечание очень дельное! с этим надо быть осторожным )
Но во многих случаях, язык позволяет избежать лишних удивлений, явно используя Function.prototype.bind или вовсе так:Оставляя в стороне «явные» отличия в поведении обычных и стрелочных функций (от которых у Гвидо волосы на спине бы встали дыбом), this настолько не стыкуется с синтаксисом классов, что надо или выпилить bind (=сделать код обратно несовместимым), или добавить self.
setTimeout(() => this.n += 1, 1000);
Утрированный пример: допустим, есть графики D3 или highcharts, которые используют контекст в своих колбеках на всю катушку, и «старый» класс с классическим that = this, который строит конфигурацию для графика:
function Config () {
let self = this;
self.field = 'foo';
this.getConfig = function() {
return {
tooltip: {
formatter: function () {
return 'Value of ' + self.field + ' for X=' + this.x + ' is ' + this.y;
}
}
}
}
}
Если всё это дело попытаться переписать с использованием «новых» классов, сразу возникают нестыковки:
class Config {
constructor() {
this.field = 'foo';
}
getConfig() {
return {
tooltip: {
// Так потеряется значение this.field
formatter: function () {
return 'Value of ' + this.field + ' for X=' + this.x + ' is ' + this.y;
},
// Так станут недоступными this.x и this.y
formatter: () => {return 'Value of ' + this.field + ' for X=' + this.x + ' is ' + this.y},
}
}
}
}
Но как же хорошо, что в JS существует столько явных возможностей, среди которых есть даже IIFE. Так язык позволяет избежать лишних удивлений:
formatter: (self => function() {return 'Value of ' + self.field + ' for X=' + this.x + ' is ' + this.y})(this)
(Да, это потому, что либы писались ещё за царя Гороха. Но самое страшное, что так продолжают писать! Потому что пока в языке есть этот чёртов this, каждый будет вертеть им как хочет)
Оох… этот контекст в highcharts! Библиотеки — это действительно отдельная тема )
Я разделяю недовольство по поводу нечистой стрелочной функции с this в примере, но готов иногда пойти на это ради читаемости.
Призыва переписывать все на классы не было. Но если бизнес-логика это позволяет, то пусть это будут классы… а не жгучая смесь подходов и танцы вокруг контекста.
Я бы не относил IIFE к явным возможностям ) но это повсеместная штука, ее трудно игнорировать. Мысль была хотя бы не спорить о синтаксисе.
Так надо же добавить тот самый self = this первой строчкой в getConfig…
Хотя автор конечно безусловно прав в утверждении, что и на JS можно понятно писать.
Сделать поля приватными на уровне модуля на данный момент можно так:
const nameField = Symbol('name');
class Foo {
constructor(name) {
this[nameField] = name;
}
toString() {
return `Hello, ${this[nameField]}`;
}
}
const foo = new Foo('world');
Object.getOwnPropertySymbols(foo).map(sym => foo[sym]); // [ 'world' ]
на мой субъективный взгляд конечно.
Можно добавить в список как сделать не очевидно — повсеместную замену обычных функций на стрелочные.
соблюдают ли такую практику разрабочтики других языков
Такого сочетания платформы, поддерживающей один язык и ее популярности нет, пожалуй, нигде в других областях программирования.
как правило всякие неявные фишки языка используют в исключительных ситуациях.
в javascript я часто встречаю
if (foo === void 0)
неужели это всегда необходимо? все же
if (typeof(foo) === 'undefined')
намного читабельнее и понятнее
Потому что когда не надо — обычное "== null" таки куда понятнее.
Постараюсь ответить более развернуто.
Одно из правил в программировании гласит что нужно уменьшать сложность. Код должен читаться как книга, конечно есть вещи которые нужно изучить для понимания ЯП, с этим я не спорю.
как одни из примеров:
()();
да я понимаю зачем это нужно, но жестить всегда, потому как "так позволяет язык, так пишут во фреймворках...", без каких либо оснований нет(я про void 0
если что… и подобное...).
Я просто согласен с автором статьи, что сумасшедшие фишки языка нужны в библиотеках, фреймворках и т.д., они там нужны для того что бы их код не превратился бутылочное горлышко, но зачем пытаться пихать это все в код который не критичен к этому, это действительно похоже на выпендреж.
понятно что идеальных языков не бывает. Я не побоюсь этого слова, но меня иногда это бомбит, я общаясь с программистами которые пишут на javascript и они часто говорят что "без этого можно было обойтись"
как-то так...
if (foo == null)
void 0 это со времен когда глобального свойства undefuned не было в стандарте и последнее могло резолвиться во что угодно.
window.undefined = 42 // happy debugging, suckers
В современных средах undefined это неизменяемое свойство и использовать его в большинстве случаев безопасно. Кроме, пожалуй, кода в eval.
Вариант с typeof может работать медленнее, т.к сравнивает строки посимвольно.
В современных средах undefined это неизменяемое свойство и использовать его в большинстве случаев безопасно. Кроме, пожалуй, кода в eval.
А нифига. undefined все такой же небезопасный. Ну разве что слегка менее небезопасный.
console.log(undefined === void 0); // true;
(function () {
var undefined = 42;
// a lot of code;
console.log(undefined === void 0); // false;
})();
деклорацию-> декларацию
Явные возможности JavaScript