Явные возможности JavaScript

    Image


    Начитывая очередную статью про малоизвестные фичи языка JavaScript и втихую пописывая какие-то невменяемые решения в консоли браузера, я часто проговариваю в голове мол ну на проде то конечно все не так!? Ведь язык давно обзавелся огромнейшим комьюнити и имеет удивительно широкий охват промышленной разработки. Раз так, то почему же мы часто забываем про его возможность быть понятным для каждого и буквально пропагандируем все эти специфичные и "запоминаемые" конструкции? Just make it Obvious!


    Рассуждения на тему


    Эту графоманию можно пропустить.


    Если говорить о промышленной разработке, то в подавляющем большинстве случаев требование к коду быть поддерживаемым даже важнее, чем решать поставленную бизнесом задачу. Для многих это очевидно, для некоторых — отчасти (встречаются конечно и редкие Д'Артаньяны). Чем понятнее наш код, тем меньше рисков для него — попасть на пыльную полку, а для нас и наших преемников — заработать проблем с нервной системой.


    Не секрет, что JavaScript удивителен своей гибкостью, что является как его величайшим достоинством, так и досадным проклятием. Путь JavaScript-разработчика долог и крайне интересен: мы поглощаем книжку за книжкой, статью за статьей и набираемся уникального опыта, но местами — действительно language-специфичного. Широчайшее распространение языка и в то же время богатое число накопившихся и подкармливаемых неочевидностей способствуют образованию двух фронтов: тех, кто едва ли не боготворит этот язык, и тех, кто смотрит на него как на неуклюжую и качающую права утку.


    И все бы ничего, но часто представители обоих фронтов работают на одном проекте. И обычной, всеми принятой практикой является непонимание (нежелание понимать и даже игнорирование) кода друг друга. И в самим деле, "я же на Java-разработчика устраивался, а не это ваше!". Масла в огонь подливают и сами JavaScript-последователи мол "никто на самом деле не знает JavaScript!" да "я могу это в одну строчку написать на js!". Каюсь, что и сам злоупотребляю на досуге ненормальным программированием...


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


    Я никого не призываю "фулстекнуться" или "T-шейпнуться" (как сейчас правильно говорить?), но почему бы нам немного не приподнять этот занавес хотя бы со стороны JavaScript-сообщества? Для этого достаточно лишь привнести немного явности в наш код, используя гибкость языка не чтобы выпендриться, а чтобы нас понимали.


    Взросление и принятие ответственности


    Со своей стороны JavaScript уже давно осознал свою роль не как язык для интерактивности интернет-страничек и "склеивания" их ресурсов, но как мощнейший и достаточный инструмент создания полноценных кросс-платформенных и часто очень даже масштабируемых приложений.


    Изначально разработанный для веб-дизайнеров этот "самый неправильно понятый язык программирования" долгое время топтался на месте, несмотря на стремительно растущую популярность и значимость. За 13-14 лет, предшествующие редакции ECMAScript 5.1, трудно вспомнить какие-то важные изменения в стандарте или понять вектор его развития. В то время огромный вклад в формирование экосистемы языка вносило его комьюнити: Prototype, jQuery, MooTools и проч. Получив эту обратную связь от разработчиков, JavaScript проделал значительную работу над ошибками: громкий 6-летний релиз ES6 в 2015 году и теперь уже ежегодные релизы ECMAScript, благодаря переработанному комитетом TC39 процессу внесения новых возможностей в спецификацию.


    Что ж, когда наши приложения стали достаточно большими, прототипная модель ООП для описания пользовательских типов перестала себя оправдывать из-за непривычного подхода. Ну серьезно, что это?


    function Animal() {
    /* Call me via new and I will be the constructor ;) */
    }
    function Rabbit() {}
    
    Rabbit.prototype = Object.create(Animal.prototype);
    Rabbit.prototype.constructor = Rabbit;

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


    class Animal {
        constructor() {
        /* Obviously, the constructor is here! */
        }
    }
    class Rabbit extends Animal {}

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


    В то же время, в языке, где функция является объектом первого порядка и имеет место постоянная событийность, совершенно обычное дело:


    let that = this;
    setTimeout(function() {
        that.n += 1;
    }, 1000);

    И тут начинаются объяснения о контекстах this и замыкании в JavaScript, что отпугивает каждого второго внешнего разработчика. Но во многих случаях, язык позволяет избежать лишних удивлений, явно используя Function.prototype.bind или вовсе так:


    setTimeout(() => this.n += 1, 1000);

    У нас тоже появились стрелочные функции, и это действительно — функции, а не функциональные интерфейсы (да, Java?). Вместе с расширенным набором методов работы с массивом они также помогают писать привычный декларативный пайплайн вычислений:


    [-1, 2, -3, 4]
      .filter(x => x > 0)
      .map(x => Math.pow(2, x))
      .reduce((s, x) => s + x, 0);

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


    function ping(host, count) {
        count = count || 5;
        /* send ping to host count times */
    }

    Сначала проходящий мимо задастся вопросом мол вероятно функция может принимать только первый аргумент, а потом мол какого черта в этом случае count становится булевом!? И действительно, функция имеет два варианта использования: с указанием count и без. Но это совершенно неочевидно: приходится смотреть в реализацию и понимать. Разобраться может помочь использование JSDoc, но это не общепринятая практика. И здесь JavaScript пошел навстречу, добавив поддержку не перегрузки, но хотя бы дефолтных параметров:


    function ping(host, count = 5) { /* ... */ }

    Резюмируя, JavaScript обзавелся огромным числом привычных вещей: генераторы, итераторы, коллекции Set и словари Map, типизированные массивы, да даже регулярные выражения начали радовать поддержкой lookbehind! Язык делает все, чтобы быть пригодным для многих вещей и стать дружелюбным для всех.


    Благоприятный путь к очевидному


    Сам язык — безусловно молодец, и с этим трудно спорить! Но что не так с нами? Почему мы постоянно напоминаем всему миру, что JavaScript все таки какой-то не такой? Давайте посмотрим на примеры некоторых широко используемых приемов и зададимся вопросом их целесообразности.


    Приведение типов


    Да, JavaScript обладает динамической и слабой системой типов и позволяет проводить операции над чем угодно, неявно выполняя за нас преобразования. Но часто явное приведение типов нам все таки необходимо и можно наблюдать следующее:


    let bool = !!(expr);
    let numb = +(expr);
    let str = ''+(expr);

    Эти трюки известны каждому JavaScript-разработчику и мотивируются они тем, что мол так можно "быстро" превратить что-то во что-то: под быстротой здесь понимается короткая запись. Может еще и false записывать сразу как !1? Если разработчик так сильно переживает за печатаемые символы, то в его любимой IDE можно без труда настроить необходимый live template или автокомплит. А если — за размер публикуемого кода, то мы всегда прогоняем его через обфускатор, который знает получше нашего как все это обесчеловечить. Почему не так:


    let bool = Boolean(expr);
    let numb = Number(expr);
    let str = String(expr);

    Результат — такой же, только понятен всем.


    Для строковых преобразований у нас есть toString, но для численных есть интересный valueOf, который может быть тоже переопределен. Классический пример, который вводит в ступор "непосвященных":


    let timestamp = +new Date;

    Но ведь есть у Date известный метод getTime, давайте использовать его:


    let timestamp = (new Date()).getTime();

    или готовую функцию:


    let timestamp = Date.now();

    Абсолютно незачем эксплуатировать неявное приведение типов.


    Логические операторы


    Отдельного внимания достойны логические операторы И (&&) и ИЛИ (||), которые в JavaScript не совсем логические: принимают и возвращают значения любого типа. Вдаваться в детали работы вычислителя логического выражения не будем, рассмотрим примеры. Ранее представленный вариант с функцией:


    function ping(host, count) {
        count = count || 5;
        /* ... */
    }

    Вполне может выглядеть следующим образом:


    function ping(host, count) {
        // OR arguments.length?
        if (typeof count == 'undefined') {
            count = 5;
        }
        /* ... */
    }

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


    Это скорее кажется дикостью для разработчика, который изначально выбрал путь JavaScript. Но для большинства других — вот этот код действительно дикий:


    var root = (typeof self == 'object' && self.self === self && self) ||
        (typeof global == 'object' && global.global === global && global);

    Да, это компактно, и да, это могут позволить себе популярные библиотеки. Но, пожалуйста, давайте не злоупотреблять этим, так как наш код будут читать не контрибьюторы в JavaScript, а разработчики, решающие бизнес-задачи за выделенные сроки.


    Может встретиться и вовсе такой паттерн:


    let count = typeof opts == 'object' && opts.count || 5;

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


    Если же мы пишем функцию-предикат, которую передаем в тот же Array.prototype.filter, то обернуть возвращаемое значение в Boolean — это хороший тон. Сразу становится очевидно назначение этой функции и не возникает диссонанса у разработчиков, языки которых имеют "правильные" логические операторы.


    Побитовые операции


    Распространенный пример проверки наличия элемента в массиве или подстроки в строке с помощью побитового НЕ (NOT), который предлагается даже некоторыми учебниками:


    if (~[1, 2, 3].indexOf(1)) {
        console.log('yes');
    }

    Какую проблему это решает? нам не приходится осуществлять проверку !== -1, так как indexOf получит индекс элемента или -1, а тильда прибавит 1 и поменяет знак. Тем самым выражение будет оборачиваться "ложью" в случае индекса -1.


    Но избежать дублирования кода можно и по-другому: вынести проверку в отдельную функцию какого-нибудь utils-объекта, как это делают все, чем использовать побитовые операции не по назначению. В lodash для этого есть функция includes, и работает она не через жопу тильду. Можно возрадоваться, так как в ECMAScript 2016 закрепился метод Array.prototype.includes (у строк тоже есть).


    Но не тут-то было! Еще тильду (наравне с XOR) используют для округления числа, отбрасывая десятичную часть:


    console.log(~~3.14); // 3
    console.log(2.72^0); // 2

    Но ведь есть parseInt или Math.floor для этих целей. Побитовые операции здесь удобны для быстрого набора кода в консоли, так как они к тому же имеют низкий приоритет перед остальной арифметикой. Но на код-ревью такое лучше не пропускать.


    Синтаксис и конструкции языка


    Некоторые странные практики трудно отнести к какому-то конкретному разделу. Например, говорят, что скобки при вызове конструктора необязательны и следующие два выражения идентичны:


    let rabbit = new Rabbit();
    
    let rabbit = new Rabbit;

    И это действительно так! но зачем создавать вопрос на пустом месте? Не каждый язык может похвастать такой "особенностью". А если все таки хочется, то пусть это будет соглашением по всему проекту. Иначе возникает ложное чувство, что есть какая-то разница.


    Похожая ситуация с объявлением набора переменных. Синтаксис директив var и let позволяет объявить (и определить) сразу несколько переменных, перечисленных через запятую:


    let count = 5, host, retry = true;

    Кто-то использует переводы строк для читаемости, но в любом случае такой синтаксис — не частое явление в популярных языках. Никто не даст по рукам и не спросит, если написать так:


    let count = 5;
    let retry = true;
    let host;

    Опять таки, если есть соглашение о хорошем стиле на уровне проекта/компании, то вопросов нет. Просто не надо чересчур комбинировать варианты синтаксиса по настроению.


    Есть в языке и вовсе специфичные конструкции, как например IIFE — позволяет вызвать функцию сразу по месту ее определения. Весь трюк в том, чтобы парсер распознал функциональное выражение, а не декларацию функции. И это можно сделать уймой разных способов: классически обернув скобками, через void или любой другой унарный оператор. И в этом нет ничего замечательного! Необходимо выбрать единственный вариант и не отходить от него без необходимости:


    (function() {
    /* ... */
    }());

    Не надо использовать операторы, чтобы хакнуть парсер. Когда на проект приходит новичок, хочется погрузить его в бизнес-логику приложения, а не кормить объяснениями откуда были подсмотрены все эти восклицательные знаки и войды. Есть еще вторая классическая запись через скобки и интересный комментарий от Крокфорда по этому поводу.


    Появление синтаксиса классов в ES6 не было сопровождено привычными модификаторами доступа. А иногда разработчику хочется и на классах пописать, и приватность соблюсти. Что приводит к такому коду Франкенштейна:


    class Person {
        constructor(name) {
            let _name = name;
            this.getName = function() { return _name; }
        }
        toString() {
            return `Hello, ${this.getName()}`;
        }
    }

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


    Подытоживая, здравой мыслью будет поделиться принятым в проекте стайл-гайдом, конфигом для линтера или просто фрагментами кода с коллегами, которые вносят в проект его не-JavaScript составляющую. Язык предлагает несколько вариантов буквально для каждой типовой задачи, поэтому улучшить понимание друг друга и попасть под общий знаменатель не составит труда (ну или почти).


    Злоключение


    Тема эта конечно холиварная и примеров можно привести гораздо больше, но основной посыл статьи о том, что не следует злоупотреблять неочевидностями в JavaScript там, где этого можно избежать. Природа языка — уникальна: позволяет писать как элегантные и выразительные (в меру "упоротые") решения, так и понятные и доступные для всех. Я в корне не согласен с расхожим мнением, что JavaScript "сам себя наказал" или "похоронен под грудой добрых намерений и ошибок". Потому что сейчас большую часть странностей демонстрирует не язык, а образовавшаяся вокруг него культура разработчиков и (не)равнодушных.

    Поделиться публикацией

    Похожие публикации

    Комментарии 53

      +1
      Ожидал очередную головоломку, а тут очередная статья, о том что js не идеальный. JSLint спасает от всех неоднозначных фич языка, а так вообще есть TypeScript, Flow где вообще все в рамках приличия, поэтому проблемы js — РЕШАЕМЫ и надуманы )))
        +1
        К сожалению линтером не обойтись… точки с запятой, скобки да strict equals. Многие вещи вполне допустимы для JavaScript-разработчика по самой природе языка, но со стороны очевидны не всем. И я специально не брал во внимание какое-то типизированное надмножество: у каждого свое ) но ведь можно в рамках приличия и без него.
          0
          Ну не знаю, у меня линтер справляется со всем кроме типизации. А насчет очевидности — ну тут уже зависит и от опыта. Ну проблема в js, в том что тут нельзя просто сделать deprecated конструкциям языка (потому что старые сайты должны работать в новых браузерах), поэтому и тянется легаси «неочевидностей».
            0
            Мое скромное мнение в том, что не надо постоянно ссылаться на «легаси неочевидностей», показывая кому-то свой код ) Если вся команда — это JavaScript-мастера, то вопросов нет. Иначе стоит задуматься о возможностях языка быть понятнее, которыми он в конце концов располагает и не нуждается в deprecated (почти негде).
          +1
          Практика показывает, что каждый настраивает линтер под себя, в итоге он не панацея. Проблем бы может быть с TypeScript не было, если бы ему опять таки не пришлось контактировать с библиотеками написанными на чистом js, в итоге внедрять его очень не просто, приходиться писать много типов, ну или добавлять через дженерик (а тогда теряется весь смысл в этой строгой типизации) особенно если это уже рабочий проект.
          +1
          Полностью согласен с тем, что в основном холиварят и поливают говном те, кто так и не осилил его в прошлом.
          Сейчас это очень даже выразительный и понятный язык.
          • НЛО прилетело и опубликовало эту надпись здесь
              0
              А в чем вопрос? это не идентичные функции, просто примеры. Конечно надо дополнить нужной проверкой на число, на ноль если нужно. Поинт в том, что явная проверка аргумента понятнее себя ведет нежели специфичный «логический» оператор.
                0
                Поймал себя на мысли, что не могу придумать ни одного кейса когда можно (и тем более нужно) использовать нестрогое сравнение.
                  0

                  Довольно старая статья об этом: When is it OK to use == in JavaScript?.


                  По большому счету есть кейсы когда можно, но нет кейсов — когда нужно )
                  В библиотеках часто используют "когда можно", чтобы код сократить (личное наблюдение).

              • НЛО прилетело и опубликовало эту надпись здесь
                  0
                  Там пример про значение аргумента по умолчанию в случае его отсутствия, не про валидацию.
                  +2
                  Чтобы избегать такого:
                  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;
                    0
                    Согласен ) Я поленился придумывать более сложный пример инициализации без привязки к аргументам функции: да и посыл, казалось, понятен был и так.
                    • НЛО прилетело и опубликовало эту надпись здесь
                  • НЛО прилетело и опубликовало эту надпись здесь
                      0
                      Ответ про разный результат был дан выше. Пример не об этом и мне стоило более четко выражать свою мысль и делать акцент. Постараюсь исправить ситуацию:

                      1. Верный вариант задать аргумент по умолчанию — это default parameters.
                      2. Если все таки нужно определить переменную по месту, то лучше не использовать «логический» оператор с проверкой наличия чего-либо.
                      3. Если в проверку еще добавляется валидация в несколько условий, то нормальный if statement еще более необходим. Хотелось бы верить, что это понятно (как было прокомментировано выше), но код с инициализацией переменной через кучу И и ИЛИ с проверками встречается.
                      • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          Я пару раз видел изумление, когда показывал код тому же Java-разработчику. И да, считаю это хорошей практикой читать и понимать код не только JavaScript как для себя, так и для коллег. Мне эти операторы угодили, но в js они только называются «логическими» и часто понятны только js-разработчикам.
                      +3
                      let timestamp = +new Date;
                      Но ведь есть у Date известный метод getTime, давайте использовать его:
                      let timestamp = (new Date()).getTime();

                      Вообще то, правильно будет
                      let timestamp = Date.now();
                        0
                        Уух… мне стыдно, но я об этой функции позабыл. Спасибо большое! добавил )
                        +1
                        let str = ''+(expr);
                        let str = String(expr);
                        Результат — такой же, только понятен всем.

                        строго говоря, не такой же. Если expr — это объект, у которого есть метод valueOf, то первый способ переведет в строку то, что вернул метод valueOf, а второй — то, что вернул метод toString.
                          –1
                          let d = new Date;
                          ''+d; // Wed Dec 12 2018 14:47:27 GMT+0300
                          +d; // 1544615247741

                          Здесь будет строковое преобразование, так как один из операндов — явно строка. Но замечание очень дельное! с этим надо быть осторожным )

                            +1
                            Date — это исключение из правил. прежде чем писать статьи о языке, неплохо бы в учебник заглянуть.
                              0
                              Да, вы правы. Спасибо, что поставили на место.
                          +1
                          Но во многих случаях, язык позволяет избежать лишних удивлений, явно используя Function.prototype.bind или вовсе так:
                          setTimeout(() => this.n += 1, 1000);
                          Оставляя в стороне «явные» отличия в поведении обычных и стрелочных функций (от которых у Гвидо волосы на спине бы встали дыбом), this настолько не стыкуется с синтаксисом классов, что надо или выпилить bind (=сделать код обратно несовместимым), или добавить self.

                          Утрированный пример: допустим, есть графики 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, каждый будет вертеть им как хочет)
                            0

                            Оох… этот контекст в highcharts! Библиотеки — это действительно отдельная тема )


                            Я разделяю недовольство по поводу нечистой стрелочной функции с this в примере, но готов иногда пойти на это ради читаемости.


                            Призыва переписывать все на классы не было. Но если бизнес-логика это позволяет, то пусть это будут классы… а не жгучая смесь подходов и танцы вокруг контекста.


                            Я бы не относил IIFE к явным возможностям ) но это повсеместная штука, ее трудно игнорировать. Мысль была хотя бы не спорить о синтаксисе.

                              0

                              Так надо же добавить тот самый self = this первой строчкой в getConfig…

                              0
                              Это как раз та область, где явно видно силу Typescript. У TS хватает своих проблем (основная из которых — в том, что окружающий мир в основном не TS), но вот в области превращения неочевидных конструкций JS в очевидные — он прекрасен.

                              Хотя автор конечно безусловно прав в утверждении, что и на JS можно понятно писать.
                                0
                                А чем он поможет в контексте проблем описанных в статье. Все упомянутые конструкции (n || 5, +Date, ...) с тем же успехом можно использовать в TS.
                                0

                                Сделать поля приватными на уровне модуля на данный момент можно так:


                                const nameField = Symbol('name');
                                
                                class Foo {
                                    constructor(name) {
                                        this[nameField] = name;
                                    }
                                
                                    toString() {
                                        return `Hello, ${this[nameField]}`;
                                    }
                                }
                                  0
                                  Да, вариантов несколько. Попробуй только потом в этом разобраться…
                                    –1
                                    const foo = new Foo('world');
                                    Object.getOwnPropertySymbols(foo).map(sym => foo[sym]); //  [ 'world' ]
                                      0
                                      В Java тоже можно доступ к приватным полям через рефлексию получить, но это же не делает их публичными :)
                                      +1
                                      Почему бы просто не использовать префикс _ в js или модификатор private в ts.
                                      0
                                      нужно наверное завести какой-то бестпрактикс по javascript, я вот сам с ним работаю очень мало и действительно приходится пробираться через дебри законов, нюансов этого языка. Но как правило многие вещи это непонятные оптимизации и правила написания кода, и увы с читабельностью они часто разнятся, что нарушает философию уменьшения сложности.
                                      на мой субъективный взгляд конечно.
                                        0
                                        Есть Airbnb JavaScript Style Guide, не совсем best practices, но частично и их захватывает. Пожалуй, наиболее популярное соглашение в мире JS.
                                        0
                                        Использование оператора || для задания значений по умолчанию настолько распространено, что уже мало кем считается антипаттерном (при условии что нельзя заменить на параметры по умолчанию). Особенно велик соблазн использовать логические операторы в длинных цепочках.

                                        Можно добавить в список как сделать не очевидно — повсеместную замену обычных функций на стрелочные.
                                          0
                                          Со всем согласен кроме наезда на замыкания — по моему очень крутая штука.
                                            0

                                            Это очень полезная штука ) на него не было наезда: там про сохранение контекста this или про расширение свойств экземпляра класса в конструкторе.

                                            +1
                                            Идея статьи в том, что JavaScript читают и пишут, в том числе, разработчики из других языков и не нужно использовать фичи, не популярные в других языках. Но у меня зеркальный вопрос, а соблюдают ли такую практику разрабочтики других языков, чтобы их было удобно читать тем, кто привык разрабатывать на JavaScript? Почему мы должны перестраиваться? Только потому, что язык стал популярным и на нём стало писать много людей, которым лень нормально освоить синтаксис JavaScript?
                                              0
                                              Там проблемы с грамматикой, а синтаксис вполне себе си-подобный.

                                              соблюдают ли такую практику разрабочтики других языков

                                              Такого сочетания платформы, поддерживающей один язык и ее популярности нет, пожалуй, нигде в других областях программирования.
                                                0
                                                Идея в том, что JavaScript позвляет это сделать без усилий в большинстве случаев. А на той, другой стороне как минимум две проблемы: 1) часто это строгие и не динамические языки и 2) на серверной стороне слишком много языков.
                                                  0

                                                  как правило всякие неявные фишки языка используют в исключительных ситуациях.


                                                  в javascript я часто встречаю


                                                  if (foo === void 0)

                                                  неужели это всегда необходимо? все же


                                                  if (typeof(foo) === 'undefined')

                                                  намного читабельнее и понятнее

                                                    0
                                                    Это тот прекрасный код, где объективно нужно по-разному обрабатывать undefined и null, или же просто обычный выпендрёж?
                                                    Потому что когда не надо — обычное "== null" таки куда понятнее.
                                                      0
                                                      не могу ответить, так как не я этот код писал. Только приходится иногда читать
                                                        0

                                                        Постараюсь ответить более развернуто.


                                                        Одно из правил в программировании гласит что нужно уменьшать сложность. Код должен читаться как книга, конечно есть вещи которые нужно изучить для понимания ЯП, с этим я не спорю.


                                                        как одни из примеров:


                                                        ()();

                                                        да я понимаю зачем это нужно, но жестить всегда, потому как "так позволяет язык, так пишут во фреймворках...", без каких либо оснований нет(я про void 0 если что… и подобное...).


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


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


                                                        как-то так...

                                                        +1
                                                        Самый читаемый и правильный вариант, который явно прописан в спецификации вот:
                                                        if (foo == null)
                                                          +1

                                                          void 0 это со времен когда глобального свойства undefuned не было в стандарте и последнее могло резолвиться во что угодно.


                                                          window.undefined = 42 // happy debugging, suckers


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


                                                          Вариант с typeof может работать медленнее, т.к сравнивает строки посимвольно.

                                                            –1
                                                            В современных средах undefined это неизменяемое свойство и использовать его в большинстве случаев безопасно. Кроме, пожалуй, кода в eval.

                                                            А нифига. undefined все такой же небезопасный. Ну разве что слегка менее небезопасный.

                                                            console.log(undefined === void 0); // true;
                                                            
                                                            (function () {
                                                              var undefined = 42;
                                                            
                                                              // a lot of code;
                                                            
                                                              console.log(undefined === void 0); // false;
                                                            })();
                                                              +2

                                                              Это аффектает только свой код. Надо сильно захотеть и постараться, чтобы так написать.

                                                        0
                                                        деклорацию
                                                        -> декларацию
                                                          0
                                                          Спасибо, исправил!

                                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                        Самое читаемое