Ответы пользователя по тегу JavaScript
  • Ajax внутри функции, как вернуть результат запроса?

    @Faliah
    Один из вариантов - использовать deferred, который есть из коробки:
    function getEndpoint(method, url) {
      var apiBaseUrl = 'http://server.ser/mobile_app/'
      
      return function(data) {	
        
        return $.ajax({
          url: apiBaseUrl + url,
          type: method,
          dataType: 'json',
          data: data
        })
      }
    }
    
    var tryLogin = getEndpoint('POST', '/post');
    
    tryLogin({ user: 'Foo', pass: 'bar' })
      .done(function(data) { 
        if (typeof data.success != 'undefined' && data.success == 'ok') {
          console.log('try login true');    
        }
      })
      .fail(function(jqXHR, textStatus, errorThrown) {
        console.log('Ошибка: ' + textStatus + ' | ' + errorThrown);
      });
    Ответ написан
    Комментировать
  • Что делает этот участок кода?

    @Faliah
    Создает переменную c, значением которой, устанавливает анонимную функцию. Анонимная функция ожидает в качестве аргумента объект и возвращает так же объект. В случае, если в объекте, переданном в качестве аргумента, есть свойство a, которое, в свою очередь так же является объектом, и имеет свойство b, функция c вернет объект с одним свойством b и значением, скопированным из одноименного свойства объекта a.
    // c :: Object -> Object
    
    console.log( c({ a: { b: 'foo' } }) ) // -> Object {b: "foo"}


    В любых других случаях вернется объект
    { b: undefined }
    Ответ написан
    Комментировать
  • Почему без return function код не работает?

    @Faliah
    В данном случае вы получаете своего рода фабрику счётчиков. При каждом вызове makeCounter() возвращается ссылка на объект фунции, а не на её результат. Так же в данном примере используется замыкание, которое дает возвращаемой функции возможность обращаться к переменной currentCount, которая нахоится в родительской области видимости.
    function makeCounter() {
    
      var currentCount = 1;
    
      return function() {
        return currentCount++;
      };
    }
    
    var counter = makeCounter();
    var counter1 = makeCounter();
    
    console.log(counter()); //1
    console.log(counter()); //2
    // счётчики работают независимо друг от друга
    console.log(counter1()) //1


    Этот пример, конечно больше синтетический, зато охватывает несколько чрезвычайно важных концепций в JS, а именно: замыкания, области видимости, first-class function. First-class function, в свою очередь, означает ряд принципов, которым следуют абсолютно все функции, создаваемые в JS:
    • Каждая функция является объектом или экзмепляром объектоного типа (instance of Object type)
    • У функции могут быть свойства. К примеру запись makeCounter.foo = "bar", абсолютно валидна. Подобный подход используется для создания статических свойств функции
    • Ссылку на объект функции можно сохранить в переменной, а потом вызвать эту функцию. Как в вашем примереcounter()
    • Можно передавать функцию в качестве параметра в другую функцию
    • Функцию можно возвращать из другой функции, как в вашем примере


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

    @Faliah
    Ваш первый res.send отправляет все заголовки и тело, что завершает вес процесс запрос-ответ и закрывает возможность использовать текущий объект res для отправки чего-либо. В данном случае вам нужно убрать из кода первый вызов res.send и вы получите "Hello 2". Никаих обходов асинхронности, глобальных переменных и прочего вам не нужно. Переменная res будет и так доступна внутри коллбэка, если вы не перекрываете её где-то в области видимости.
    Ответ написан
    Комментировать
  • Как при нажатии на кнопку выводить всплывающее окно в нужных местах?

    @Faliah
    У каждой формы вы, в дополнение к position: absolute;, можете указать top:0; right: 0;, но контейнер, в котором у вас отображаются формы, должен иметь position: relative;
    Ответ написан
  • Как с помощью regexp удалить все, начиная с определенного символа?

    @Faliah
    "1 августа 2016 г. 19.00".replace(/\w+г\..*/, '')
    Или с trim, чтобы упростить регулярку:
    "1 августа 2016 г. 19.00".replace(/г\..*/, '').trim()
    Ответ написан
  • Как изменять state компонента react js извне?

    @Faliah
    Сначала мне показалось, что это извращение - использовать Реакт, вместо шаблонизатора, как из пушки по воробьям.
    Но, в самом использовании по-моему нет ничего особенного - вот тут собрал вам демку

    Вкратце:
    • Реакт не будет остлеживать состояние глобальных переменных и перерисовывать компонент при их изменении
    • Вместо этого вам нужно воспользоваться lifecycle хуками и, как предлагал коллега выше, внутри этого метода пробросить нужные методы для управления состоянием компонента наружу, хоть в тот же widnow
    • Это позволит вам импользовать одни и те же методы как в дочерних компонентах: обработка клика по оверлею или по кнопке в модальном окне, так и во внешних, по отношению к контексту Реакта, DOM элементах, или, возможно, в каких-то еще бибилиотеках, JQuery и прочих


    Если использовать мой компонент, то нужно немного изменить ваш код:
    ...
      this.on('showModal', function (data) {
        if (!window.modalAttached) {
          ReactDOM.render(
            <ModalWindow data={data} />,
            this.el
          )
        }      
        window.toggleModal();
      }
    ...
    Ответ написан
  • JS: как запретить запуск функции подряд?

    @Faliah
    Используйте debounce, чтобы не использовать дополнительных библиотек, можете взять код вот тут
    Ответ написан
    Комментировать
  • JS есть ошибка?

    @Faliah
    $ - индентификатор, используемый библиотекой jQuery. Вы не подключили эту библиотеку, либо пытаетесь выполнить код до подключения библиотеки
    Ответ написан
  • Как реализовать тип Vector?

    @Faliah
    Примерно так:
    function Vector(x,y) {
      this.x = x;
      this.y = y;
    }
    Vector.prototype.plus = function(otherVector) {
      var xx = this.x - otherVector.x;
      var yy = this.y - otherVector.y;
      return 'Vector: x= ' + xx + ' y=' + yy;
    };
    Vector.prototype.minus = function(otherVector) {
      var xx = this.x - otherVector.x;
      var yy = this.y - otherVector.y;
      return 'Vector: x= ' - xx - ' y=' - yy;
    };
    
    console.log(new Vector(1, 2).plus(new Vector(2, 3)));
    Ответ написан
  • Инициализация и определение функции Javascript?

    @Faliah
    Вот пример, наглядно демонстрирующий разницу Function Declaration и Function Expression. Основное отличие, на мой взгляд, в том, что function declaration появляется в контексте выполнения раньше всего, отсюда и доступность такой функции в любом месте области видимости. В свою очередь function expression как и остальные expression выполняется, или как в приведенном примере, присваивается значению переменной прямо во время выполнения скрипта, поэтому она доступна только после строки с присвоением и это нужно иметь в виду.
    Ответ написан
    Комментировать
  • Как получить this класса внутри его метода?

    @Faliah
    Контекст this теряется, если ваш метод вызывается не из экземпляра класса, в котором он объявлен. Нужно использовать bind, чтобы привязать функцию к экземпляру.
    const show = element => {
      element.classList.add('show');
    }
    
    class Modal {
      constructor() {
        this.modal = document.get...
      }
    
      open(endAction) {
        show(this.modal);
        
        endAction();
      }
    }
    
    class Slider {
      constructor() {
        this.overlay = document.get...;
      }
    
      openSlider() {
        show(this.overlay);
        console.log(this); // Slider
      }
    
      openModal() {
        const modal = new Modal();
    
        modal.open(this.openSlider.bind(this));
      }
    }


    Или с ES6 стрелочной функцией, результат один и тот же:

    const show = element => {
      element.classList.add('show');
    }
    
    class Modal {
      constructor() {
        this.modal = document.get...
      }
    
      open(endAction) {
        show(this.modal);
        
        endAction();
      }
    }
    
    class Slider {
      constructor() {
        this.overlay = document.get...;
      }
    
      openSlider() {
        show(this.overlay);
        console.log(this); // Slider
      }
    
      openModal() {
        const modal = new Modal();
    
        modal.open(() => this.openSlider());
      }
    }
    Ответ написан
    5 комментариев
  • Как вернуть имя анонимной функции для события?

    @Faliah
    Вернуть имя анонимной функции нельзя, на то она и анонимная. Если бы можно было написать так, как вы хотите, то это в любом случае менее читаемо, чем ваш первый вариант. Вызов инициализирующего кода и привязка обработчиков событий, выполняют разные по своей семантике операции. Мне кажется, что смешивать их - не очень хорошо.

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

    Плюс каким образом вы будете изменять или тестировать этот обработчик в будущем, если такая необходимость возникнет, а он будет использоваться в обработке разных событий?
    Ответ написан
    Комментировать
  • Как проверить клик по элементу на нативном javascript?

    @Faliah
    Посмотрите пример реализации. На блоке .wrapper висит обработчик 'click' который обрабатывает как клики по самомму элементу, так и по всем дочерним. Для проверки элемента, инициировавшего событие, используется свойство e.target, результат выводится в консоль. Данный код должен корректно работать в IE9+
    Ответ написан
  • Для чего нужен оператор двойное двоеточие ( :: ) в javascript?

    @Faliah
    Похоже вы говорите о сокращенной записи для функции .bind(), которая сейчас входит в ES7 proposal

    Вот несколько ссылок:
    Статья, описывающая работу оператора и его возможн...
    Ответ на SO
    Ответ написан
    Комментировать
  • Первое приложение на Angular, как его осилить?

    @Faliah
    Если сам опросник у вас будет храниться в памяти, то можете делать хоть на github pages. С другой стороны - применять SPA фреймворк без работы с бэкендом какого-либо вида (socket, rest) это как из пушки по воробьям. Для отрисовки и связывания компонентов вам и голого React хватило бы.

    Но ответ на ваш вопрос - не нужна
    Ответ написан
  • Как составить глубокое вложения классов в javascript?

    @Faliah
    Не совсем понял в чём вопрос. Если под "глубокое вложение классов" вы подразумеваете то, что функции-конструкторы у вас являются свойствами объектов, вложенных в другие объекты, то у вас ничего не поменяется:
    let Root = {};
    Root.Child = {};
    
    class MyClass {
      constructor(prop1, prop2) {
        this.prop1 = prop1;
        this.prop2 = prop2;
      }
    }
    
    Root.Child.MyClass = MyClass;
    
    var instance = new Root.Child.MyClass('super', 'great');
    console.log(instance);


    Если же вы имели в виду сильно вложенное наследование RootClass -> ChildClass -> ChildOfChildClass. То хотелось бы от этого предостеречь и дать несколько ссылок на английские ресурсы. Лучше сразу приучаться делать правильно (по-крайней мере так принято):

    Yuotube ролик - Composition over inheritance
    Prefer composition over inheritance
    Common Misconceptions About Inheritance in JavaScript
    3 Different Kinds of Prototypal Inheritance: ES6+ ...
    The Open Minded Explorer’s Guide to Object Composition
    The Two Pillars of JavaScript
    Ответ написан
    Комментировать
  • Есть ли простой движок для кастомных географических карт?

    @Faliah
    Есть смысл использовать популярный и поддерживаемый LeafletJS. Очень мощная библиотека, разобравшись, с которой, о проблемах связанных с картографией можно забыть
    Ответ написан
    2 комментария
  • Как причесать код?

    @Faliah
    Упростить можно всё, что угодно, просто взшлянув на проблему с другой стороны. Есть несколько вопросов по коду:
    3182804ed7444150bdab28a4ac0e5588.png

    1) В функцию redis.hmget вы передаёте две строки 'level' и code lang="javascript">'language' (в красных прямоугольниках). Нельзя ли избавиться от них, ведь, по сути это константы? То же самое касается их аналогов в красных прямоугольниках со скруглёнными уголками. Если в каждую функцию redis.hmset нужно обязательно передать 'level', то, на мой взгляд полезно было бы сделать обёртку
    function memoizeArguments() {
      
      const memoizeArgs = Array.from(arguments);
      
      return function(fun) {
        return function() {
          fun.apply(null, memoizeArgs.concat(Array.from(arguments).join()));
        }
      }
      
    }
    
    app.on('message', msg => {
      
      const telegramID = msg.from.id,
            encodedID = `id${telegramID}`,
            text = msg.text;
    
      // Сохраняем аргументы, чтобы упростить сигнатуры вызовов, создаём обертки с закэшированными аргументами
      const withId = memoizeArguments(telegramID);
      const appSendMessage = withId(app.sendMessage);
      
      const withEncodedIdAndLevel = memoizeArguments(encodedID, 'level');
      const redisHmSet = withIdAndLevel(redis.hmset);
      
      
    
      redis.hmget(encodedID, 'level', 'language', (err, res) => {
        
        let sendMessageArgs = null;
        let redisHmSetArgs = null;
        
        switch (res[0]) {
          case 'language':
            sendMessageArgs = message[text].languageGood;
            redisHmSetArgs = ['user_name', 'language', msg.text];
          break;
    
          case 'user_name':
            sendMessageArgs = [message[res[1]].nameGood, options];
            redisHmSetArgs = ['user_name', text, 'change_services']; // тут парамет 'level' передастся 2м аругментом, а не 4м
          break;
    
          case 'change_services':
            
            switch(text) {
                
              case 'some text':
                sendMessageArgs = message[res[1]].flpPhone;
                redisHmSetArgs = ['flp', 'sublevel', 'phone'];
                break;
    
              case 'another text':
                redisHmSetArgs = 'ooo';
                break;  
                
              case 'other':
                redisHmSetArgs = 'reg';
                break; 
                
              default:
                sendMessageArgs = message[res[1]].changeServicesBad;
                break;
            }
           
          break;
        }
    
        if (sendMessageArgs) appSendMessage(sendMessageArgs);
        if (redisHmSetArgs) redisHmSet(redisHmSetArgs);
        
      });
    });


    Вообще говоря логику фомирования массивов с аргументами тоже можно упростить и сделать единообразной, либо делать функции app.sendMessage и redis.hmset менее полиморфными - в разных вызовах передается разное число аргументов и иногда в разном порядке. Это сложно для понимания
    Ответ написан
    Комментировать
  • Как изменить грамотно код?

    @Faliah
    Если objectPath.del удаляет данные из obj_str, то измените код так, чтобы фукнция objectPath.del возвращала результирующий объект:
    objectPath.del = (obj, level) => {
      // тут логика удаления данных по уровню
    
      return updated_obj; // возвращаем измененный объект
    }


    После этого в коде можно пользоваться именно как вы хотели
    case DELETE_STRUCTURE_COUPLE:
          return {
            ...state,
            structure: objectPath.del(state.structure, action.level)
          };
    Ответ написан
    Комментировать