Ответы пользователя по тегу JavaScript
  • Почему модуль, собранный webpack, возвращает число при Code Split?

    youngmysteriouslight
    @youngmysteriouslight Автор вопроса
    ТК, ТТ, JS, FP, WM
    Решил свою проблему. Правда, пришлось перейти на rollup.
    // rollup.config.js
    import { nodeResolve } from '@rollup/plugin-node-resolve';
    import commonjs from '@rollup/plugin-commonjs';
    
    export default {
      external: [/node_modules/],
      input: {
        core: 'src/core',
        all: 'src/all',
      },
      output: {
        dir: 'dist',
        format: 'cjs',
        entryFileNames: '[name].js',
      },
      plugins: [commonjs(), nodeResolve()],
    };
    Ответ написан
    Комментировать
  • Как работают Function.bind.apply и function.apply.bind?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Предполагаю, что описание и принцип работы bind и apply нам известен.
    Для простоты рассуждений удобно считать, что this является как бы нулевым аргументом.
    Нам потребуется следующее: g.bind(t, x)условно эквивалентно
    function (a) {
      return g.call(t, x, a);
    }


    Что делает приведённый код

    Строго говоря, Function.apply не то же самое, что Function.prototype.apply. Но в рассматриваемом случае, как мы увидим, они взаимозаменяемы, потому что их значения совпадают (указывают на одну функцию с одним кодом).
    Function.apply.bind(f, null) возвращает функцию, грубо говоря (потому что неявно предполагается, что эта функция в будущем будет вызвана ровно с одним аргументом), такого вида
    function (a) {
      return Function.apply.call(f, null, a);
    }
    что условно (потому что здесь происходит изменение f как объекта; в действительности, вызывается apply с this=f) эквивалентно
    function (a) {
      f.apply = Function.apply;
      return f.apply(null, a);
    }
    Поскольку функция f при нормальных обстоятельствах наследует тот же apply, что и Function, Function.apply.apply(f, null, a) полностью эквивалентно f.apply(null, a).

    Почему важно указать null
    Потому что, если его не указать, получится функция
    function (a) {
      return f.apply(a);
    }
    то есть a будет передано как this.

    Это тоже может иметь смысл. Сравните:
    альтернативный пример
    function foo(bar,baz) {
      var x = bar * baz;
    
      return [
        Promise.resolve(x),
        Promise.resolve(x*2 )
      ];
    }
    
    Promise.all(
      foo( 10, 20 )
    )
    .then( Function.apply.bind(
      function() {
        console.log( this[0], this[1] );
      }
    ) );
    Ответ написан
    Комментировать
  • Конструктор прототипа?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    А есть ли смысл указывать для дочернего объекта конструктор прототипа, я так понимаю это только ссылка на функцию, и если его необязательно использовать?
    У каждого конструктора есть прототип. По умолчанию это Object.prototype.
    Если Вам нужен прототип, указывайте. Если не нужен, но и не за чем. Очевидно же.
    Только одна поправка: прототип это объект, который (как и прочие объекты) состоит из полей, среди которых есть функции.

    Как лучше всего добавлять в прототип свои свойства
    Я не знаю. ИМХО, для прикладных задач лучше делать так, чтоб читало проще.

    Как лучше добавлять свои методы, вариант только так, или есть более элегантное решение, например создать объект со своими методами и склеить его с прототипом?
    Без разницы, но нужно учитывать один момент.
    Пусть мы определили конструктор Son и ему задали Son.prototype тем или иным образом. Для простоты положим, что прототип состоит только из функций. Затем создали несколько экземпляров (new Son).
    Далее, предположим, мы хотим добавить в прототип новый метод или изменить существующий.
    Здесь необходимо решить, будем ли (1) мы менять прототип уже созданных экземпляров или же (2) у созданных экземпляров оставим их старый прототип, а у создаваемых будет уже новый.

    P.S. наконец, в последних редакциях появились новые синтаксические конструкции. О них тоже забывать не нужно.
    Ответ написан
  • Как сделать наследование базового класса?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Есть такое. Опера, например, кричит:
    Unhandled Error: String.prototype.toString: this is not a String object

    Согласно спецификации toString кидает исключение, если this не является строкой, то есть грубо
    String.prototype.toString = function() {
      if (typeof this === 'string')
        return this.valueOf();
      else
        throw new TypeError();
    };

    Чтобы можно было наследовать от String, нужно переопределить метод.

    P.S. я не могу объяснить, почему код с extend работает.
    Ответ написан
  • Одинаковы ли два кода?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Если promise разрешается с не-промисным значением value, то promise.then(value => value) и promise.then(value => Promise.resolve(value)) эквивалентны promise в приведённой выше цепочке.
    Статусы этих промисов одинаковы.

    Если promise разрешается с промисным значением value, то promise.then(value => value) и promise.then(value => Promise.resolve(value)) эквивалентны: они вернут промис, который разрешается со значением, с которым разрешается value.

    P.S. честно говоря, я не знаю, как сделать промис, который бы разрешался со значением, который сам по себе является промисом. Беглое лурканье и SO подсказывают, что это невозможно, разве только будем оборачивать возвращаемый во время разрешения промис в объект (ссыль)
    Ответ написан
    6 комментариев
  • Есть ли разница в вызове функций?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    const d = {
      b: a.b,
      c: function() { alert('wow'); }
    };
    
    d.b();

    Пояснение на всякий случай:
    при вызове d.b() будет исполнена та же функция, что записана в a.b(), но this=d.
    Ответ написан
    Комментировать
  • Почему на клиенте используют js а не php?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Может, я и не понял контекст вопроса, но не один из предложенных вариантов ответа не отвечает на поставленный вопрос. Итак, почему же на клиенте сейчас используется JS, а не PHP?

    Кратко: так исторически сложилось.
    PHP исходно был собран как интерпретируемый скриптовый язык для серверной генерации домашних страниц, позже был превращен в полноценный инструмент для серверного программирования.
    JS был заказан ради внедрения в один конкретный браузер и впервые был анонсирован перед выпуском второй бета-версии Netscape Navigator. Затем он в виде диалектов перекачевал в другие браузеры, ибо идея DHTML (разметка на HTML, оформление на CSS, интерактив и прочая клиентская логика на JS) понравилась многим. Затем он был стандартизован, а после 2009 начался треш.

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

    В нашей же пытаются сделать обратную вещь: запустить JS на сервере, чтобы и на клиенте, и на сервере был один язык (гуглите: изоморфный JS). Шансов, что на браузере будут нативно исполняться PHP скрипты, равны нулю. Даже dart не прижился.
    Ответ написан
    Комментировать
  • Как будет выглядеть callback функция?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Задача:
    есть изменяющаяся во времени среда, нужно запустить асинхронный процесс, который будет периодически проверять некоторое условие и, если оно выполняется, единожды вызовет функцию и завершится.
    // условие, когда нужно исполнить функцию и завершить процесс
    function readIsOK(read) {
      return read != last_read;
    }
    
    // какие-то осмысленные действия, когда условие удовлетворяется
    function doSomething(result) {
      if (last_read < result) {
            //...тут какой-то код
      } else if (last_read > result) {
            // ...тут какой-то код
      }
    }
    
    // функция, которая запускает процесс
    function start() {
      // функция, которая ежесекундно проверяет условие
      // если условие выполняется, делает полезное действие
      // иначе процесс продолжается до следующего вызова checkRead
      function checkResult() {
        var result = getRead();
        if(readIsOK(result)) doSomething(result);
        setTimeout(checkResult, 1000);
      }
      // запускаем первую итерацию
      checkResult();
    }
    
    start();

    Этот код принципиально ничем не отличается от Вашего.
    Что мы можем хотеть сделать? Абстрагироваться от doSomething и last_read. На данный момент они являются внешними параметрами.
    Абстракция от doSomething и будет колбеком, который Вы желаете.
    // условие, когда нужно исполнить функцию и завершить процесс
    function readIsOK(read) {
      return read != last_read;
    }
    
    // какие-то осмысленные действия, когда условие удовлетворяется
    function doSomething(result) {
      if (last_read < result) {
            //...тут какой-то код
      } else if (last_read > result) {
            // ...тут какой-то код
      }
    }
    
    // функция, которая запускает процесс
    function start(callback) {
      // функция, которая ежесекундно проверяет условие
      // если условие выполняется, делает полезное действие
      // иначе процесс продолжается до следующего вызова checkRead
      function checkResult() {
        var result = getRead();
        if(readIsOK(result)) callback(result);
        setTimeout(checkResult, 1000);
      }
      // запускаем первую итерацию
      checkResult();
    }
    
    start(doSomething);

    Теперь можно сделать, например,
    start(() => start(() => alert("hi!")));
    Так после окончания первого процесса запустится второй, после окончания которого будет сообщение.

    Важный момент: Вам, вероятно, захочется после каждого процесса запускать следующий, используя вместо last_read значение предыдущего result. Для этого необходимо абстрагироваться от last_read. Передача между двумя процессами уже реализована.
    Ответ написан
    Комментировать
  • Деструктуризация?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Babel немного проясняет этот вопрос.

    Как мне кажется, на данный момент поведение в таких случаях зависит от интерпретатора. Если интересует поведение, которое должно быть по спецификации ES6, открывай её и читай там.
    Ответ написан
  • Как улучшить код?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Насколько я представляю, если не вводить дополнительные переменные, то только
    function adjacentElementsProduct (inputArray) {
        return inputArray
            .sort()
            .slice(-2)
            .reduce((total, num) => total * num);
    }

    Если с доп. переменными, то
    function adjacentElementsProduct (inputArray) {
        const [ x, y ] = inputArray
            .sort()
            .slice(-2);
        return x * y;
    }

    Ну и как намекнул iamevg_, можно поиграться с пробельными символами.
    P.S. учтите, что для Вашей задачи можно выбрать более оптимальный алгоритм.
    Ответ написан
    3 комментария
  • Как получить аргументы из конструктора в классе?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    А что Вы хотите? Вы вызываете new Clock с одним аргументом, а в теле используете два. Поэтому options принимает значение переданного объекта с полями template и name, а sub -- undefined.

    Скажите, чему, по Вашему желанию, должны равняться options и sub в этом примере.
    Ответ написан
    3 комментария
  • Метод прототипа это instance member или static?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Традиционно методы прототипа относят к статичным.

    Если сравнивать прототипную организацию объектов и классовую, все поля (и, как следствие, методы) прототипа едины для всех объектов с этим прототипом (если они не имеют собственных полей с тем же ключом), то есть два разных объекта с одним прототипом имеют одинаковое значение тех полей, значение которых определяется прототипом. Это соответствует статичным членам класса, которые так же являются едиными для всех экземпляров класса.
    Ответ написан
    Комментировать
  • Как правильно написать jsdoc для кода внутри самовызывающейся функции?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    У меня код, написанный по первому варианту Alex Ander, не даёт нужный результат.
    Код, который не связывает имена с пространством имён
    /**
     * @namespace ZZZ
     */
    (function() {
      /** @lends ZZZ */
      
      /**
       * my function.
       */
      function f() {
      }
      
      /**
       * my variable.
       */
      var x = 2;
      
    })();

    Вот моё предложение:
    /**
     * @namespace ZZZ
     */
    (/** @lends ZZZ */function() {
    
      /**
       * my function.
       */
      function f() {
      }
      
      /**
       * my variable.
       */
      var x = 2;
      
    })();

    Этот код добавляет имена с атрибутом inner (т.е. ZZZ~f, ZZZ~x), причём явное указание static или instance не менияет этого, разве что только явно не указан memberof, как во втором примере Alex Ander.
    В целом, lends непосредственно перед функцией function() {} добавляет все имена на верхнем синтаксическом уровне в модуль/класс/неймспейс с атрибутом inner.
    Ответ написан
    Комментировать
  • Чем отличается scope от лексического окружения?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Выскажу мнение: я всегда считал, что это одно понятие.

    Scope — это окружение, в котором исполняется код функции, когда функция вызывается обычным образом.
    Для обеспечения статического связывания переменных и аргументов, которое также называется лексическим замыканием, спецификация JS предполагает, что во время создания функции-как-объекта у неё появляется поле [[Scope]], которое содержит контекст исполнения, в котором функция создана, и в качестве прототипа использует [[Scope]] контекста (обычно, [[Scope]] той функции, в теле которой создана рассматриваемая функция). Когда функция вызывается, она использует этот свой [[Scope]] для того, чтобы создать контекст исполнения своего кода.
    Подробнее: javascript.ru/ecma/part10 (намеренно даю ссылку на 3-ю редакцию)
    Поэтому мне не понятно, почему кто-то говорит, что scope не существует, когда его существование явно требуется спецификацией языка. Разве что в том смысле его не существует, что интерпретатор не обязан явно этот объект создавать, но и об этом спецификация говорит.
    Ответ написан
    Комментировать
  • Как правильно задокументировать код JSDoc?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    JSDoc 3.5.5
    /** @module ZModule */
    (function() {
    
    /**
     * an array of instances.
     * @memberof module:ZModule
     */
    var instances = [];
    
    /**
     * retrieve an instance.
     * @memberof module:ZModule
     * @return an instance
     */
    function getInstance() { return instance[0]; }
    
    /**
     * Constructor of a new instance.
     * @memberof module:ZModule
     * @class module:ZModule.createInstance
     */
    function createInstance() {
       return /** @lends module:ZModule.createInstance# */ {
           /**
            * param.
            */
           objParam1: 42,
           /**
            * method.
            * @return an integer
            */
           objMethod1: function() { return 24; }
       }
    }
    
    window.myModules.myModule1 = {
       instances: instances,
       createInstance: createInstance,
       getInstance: getInstance
    }
    
    })();
    Ответ написан
    Комментировать
  • Как переназначить события onclick после выполнения функции?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    Вы можете перенести проверку класса родителя и разделение логики present/udalitCol в сам обработчик события, поскольку при вызове доступна ссылка на элемент, по которому был произведён клик.
    // цикле без if-условия
    kompListItem[i].onclick = function() {
      if (this.parentNode.className !== 'added-to-table')
        return present.call(this);
      else
        return udalitCol.call(this);
    };


    Альтернативно, Вы можете добавить вызов init в конец функции present, но учтите, что все свободные имена этой функции (kompListItem, i) необходимо перед вызовом обновить или другим, соответствующим логике приложения образом обработать.
    Ответ написан
    Комментировать
  • Цифровые свойства объекта?

    youngmysteriouslight
    @youngmysteriouslight
    ТК, ТТ, JS, FP, WM
    for(k in { x: 1, y: 2 }) { ... }
    k примет значения "x" и "y" в теле.
    Поскольку массив является объектом с ключами, которые являются числами, в цикле for(k in [1, 2]) { ... } k пройдёт значения "0" и "1".
    Однако, объект-массив содержит ещё некоторые поля, например, "length", который, однако, не проходит итератор. Если я правильно помню, в ES3 это было жестко вшито в семантику языка как исключение, а в ES5 это обыгрывается тем, у полей появились атрибуты, причём поле "length" имеет дескриптор enumerable.

    В процитированном фрагменте говорится буквально следующее: слева от in не обязательно будет экземпляр Array, даже если у этого объекта есть поля "0", "1" и т.п., при этом могут быть и другие поля, которые имеют заранее неизвестные дескрипторы. И стоит быть готовым к тому, что k в цикле for(k in obj) {...} может принять строковое значение, которое нельзя привести к числу.
    Ответ написан
    Комментировать