Ответы пользователя по тегу JavaScript
  • Почему среднее значение разное?

    rockon404
    @rockon404
    Frontend Developer
    range создает диапазон range(n, m) по формуле:
    n, n + 1, n + 2, ..., n + m - 1

    В первом случае диапазон от 1 до 5, так как 1 + 5 - 1 = 5:
    1, 2, 3, 4, 5
    Во втором случае диапазон от 0 до 4, так как 0 + 5 - 1 = 4:
    0, 1, 2, 3, 4

    Сумма в первом случае:
    { sum: 15, count: 5 }
    во втором:
    { sum: 10, count: 5 }

    Другими словами n - это первое значение диапазона, m - количество элементов входящих в диапазон.

    Результат, в первом случае:
    x = 15 / 5;
    во втором:
    x = 10 / 5;
    Ответ написан
    Комментировать
  • Как реализовать ссылки на пункты из списка, чтобы пункты открывались в отдельном div для редактирования CRUD React?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Cмотря как хотите реализовать. Если хотите открывать на той же странице, то достаточно хандлера, ключа состояния и условия в render:
    class Example extends Component {
      state = {
         eventsList,
        selectedEvent,
      };
    
      handleSelectEvent(event) {
         this.setState({ selectedEvent: event });
      }
      
      render() {
        const { eventsList, selectedEvent } = this.state;
                    
        return (
          <Wrapper>
            {selectedEvent && <EventDetails event={selectedEvent} />}
            <ul>
              {eventsList.map(event => (
                <li
                  key={event.id}
                  onClick={() => this.handleSelectEvent(event)}
                >
                  {event.name}
                </li>
              ))}
            </ul> 
          </Wrapper>
        );
      }
    }


    Если хотите на отдельной странице, то лучше использовать роутер.
    В примере ниже используются компоненты BrowserRouter, Switch, Route, Link из пакета react-router-dom.
    Приложение оборачиваете в BrowserRouter:
    <BrowserRouter>
      <App />
    </BrowserRouter>

    В том месте где хотите рендерить роуты:
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/events" component={EventsList} />
      <Route path="/event/:id" component={EventDetails} />
    </Switch>

    В компоненте списка:
    class EventsList extends Component {
      state = {
         eventsList,
      };
    
      render() {
        const { eventsList } = this.state;
                    
        return (
          <Wrapper>
            <ul>
              {eventsList.map(event => (
                <li key={event.id}>
                  <Link to={`/event/${event.id}`}>{event.name}</Link>
                </li>
              ))}
            </ul> 
          </Wrapper>
        );
      }
    }


    В компоненте детализации, в зависимости откуда получаете элементы реализация может отличаться,
    но id элемента можно получить из параметров ссылки так:
    class EventsList extends Component {
      componentDidMount() {
        const elementId = this.props.match.params.id;
      }
      render() {
        ...
      }
    }
    Ответ написан
  • Как правильно создать класс?

    rockon404
    @rockon404
    Frontend Developer
    Пусть инпуты меняют только значения this.playersCount, this.cardsCount и this.numbersCount.
    Никаких id для игроков не надо, пусть они просто лежат в массиве. Создавайте по клику на кнопку "создать игру" или "создать карточки":
    class Game {
       // some stuff
    
      createGame() {
        this.players = [];
    
        for (let i = 0; i < this.playersCount; i++) {
         const player = new Player({
            name: `Player ${i}`,
            cards: this.createCards()
          });
       
          this.players.push(player);
        }
      }
    
      createCards() {
        // some stuff
      }
    
      // some stuff
    }
    Ответ написан
    3 комментария
  • Почему не проходит новый синтаксис?

    rockon404
    @rockon404
    Frontend Developer
    export default (state = initState, action) => {
        if(action.type === 'ADD_VAL'){
            return [
                ...state,
                action.date
            ];
        }
        return state;
    };

    либо:
    const values = (state = initState, action) => {
        if(action.type === 'ADD_VAL'){
            return [
                ...state,
                action.date
            ];
        }
        return state;
    };
    
    export default values;


    Второй вариант предпочтительнее, так как именованные функции легче отлаживать.
    Ответ написан
    1 комментарий
  • Как сформировать массив?

    rockon404
    @rockon404
    Frontend Developer
    ES6:
    const map = {};
    
    srcArray.forEach(({ ID, ...Coords }) => {
      map[ID] = map[ID] || { ID, Coords: [] };
      map[ID].Coords.push(Coords);
    });
    
    const resultArray = Object.values(map);

    или без rest оператора:
    const map = {};
    
    srcArray.forEach(({ ID, lat, lng }) => {
      map[ID] = map[ID] || { ID, Coords: [] };
      map[ID].Coords.push({ lat, lng });
    });
    
    const resultArray = Object.values(map);

    еще ES6:
    const resultArray = 
      Object.values(srcArray.reduce((map, { ID, ...Coords }) => {
        map[ID] = map[ID] || { ID, Coords: [] };
        map[ID].Coords.push(Coords);
    
        return map;
      }, {}));

    без использования rest:
    const resultArray = 
      Object.values(srcArray.reduce((map, { ID, lat, lng }) => {
        map[ID] = map[ID] || { ID, Coords: [] };
        map[ID].Coords.push({ lat, lng });
    
        return map;
      }, {}));


    ES5:
    var map = {};
    var resultArray = [];
    
    srcArray.forEach(function(el) {
      map[e.ID] = map[el.ID] || { ID: el.ID, Coords: [] };
      map[el.ID].Coords.push({ lat: el.lat, lng: el.lng });
    });
    
    for(var key in map) {
      resultArray.push(map[key]);
    }
    Ответ написан
    Комментировать
  • Как вызвать alert() при пропадании выделения (slection) с текста?

    rockon404
    @rockon404
    Frontend Developer
    Можно так:
    var prevSelection;
    
    document.addEventListener('mouseup', function() {
      var selection;
      
      if (window.getSelection) {
        selection = window.getSelection().toString();
      } else if (document.selection) {
        selection = document.selection.createRange().text;
      }
      
      if (!selection && prevSelection.length) {
        alert('Text uselected');
      }
      
      prevSelection = selection;
    });

    Демо.
    Ответ написан
    2 комментария
  • Почему перезаписывается массив?

    rockon404
    @rockon404
    Frontend Developer
    А вы что сделать хотели?
    Ваш цикл никогда не закончится, так как вы постоянно добавляете элементы в массив. Перед каждой итерацией идет проверка:
    i < this.arr.length
    А у вас и i и this.arr.length после каждой итерации на 1 увеличиваются и как следствие this.arr.length всегда больше.

    Возможно вы хотели сделать, что-то вроде этого:
    this.httpService.getList().subscribe(data => {
      this.arr = [...this.arr, ...data];
    });

    или:
    this.httpService.getList().subscribe(data => {
      this.arr = this.arr.concat(data);
    });


    Если важно расширять старый массив, а не возвращать новый то:
    this.httpService.getList().subscribe(data => {
      data.forEach(el => this.arr.push(el));
    });
    Ответ написан
  • Какой стек выбрать для не сложного многопользовательского SPA?

    rockon404
    @rockon404
    Frontend Developer
    Для вашей задачи можно использовать React/Vue + Webpack + Koa + ReactNative/Weex + MongoDB/MySQL/GraphQL + Docker + Nginx + Git.
    1. На React вы сможете написать как само веб приложение, так и нативные мобильные клиенты под Android и IOS с помощью React Native. Можно выбрать Vue - он проще для новичка и на нем также можно писать нативные мобильные приложения c Weex. Использовать Angular не советую, так как порог вхождения у него выше, а грамотную архитектуру написать сложнее. Тут нужен опыт или советы опытного разработчика.
    2. Webpack. Как не крути, а со сборкой фронтенда вам придется разобраться. В современной разработке без этого никуда. Использовать решения вроде create-react-app, лично я не советую. Как альтернативу для быстрого старта, лучше выбрать ReKit. Это тулкит для разработки на React, содержащий в себе полноценную IDE, начальную структуру проекта с роутингом и Redux, DevServer, HMR, инструменты для тестирования и много других интересных фич, вроде аналитики. Еще в сгенерированном проекте полностью отсутствует вендорная магия, вроде react-scripts в create-react-app и у вас не будет каких либо проблем с миграцией.
    3. Если выберите Koa для сервера, вам, как минимум, не придется изучать еще один ЯП. API накидать на нем плевое дело для опытного разработчика, вам же придется изучать статьи и репозитории с примерами на github. Можно выбрать Express это предшественник Koa, и в силу возраста, статей и ответов на типовые вопросы на stackoverflow для него больше.
    4. Выбор БД не принципиален.
    5. Использование Docker так же не обязательно, но разобравшись сразу, вы во многом облегчите себе жизнь и не столкнетесь с ситуацией, что ваш проект который вроде работал локально, не хочет заводиться на удаленном сервере.
    Ну Nginx и Git думаю в представлении и обосновании мотивации к использованию не нуждаются.
    Так же, возможно, хорошим решением будет использование облачных сервисов вроде Amazon Web Services

    Прежде чем браться изучать эти инструменты вам обязательно надо хорошо изучить JavaScript, HTML и CSS.

    По приложению вам понадобится:
    1. Веб сайт с описанием сервиса и формой входа/регистрации
    2. Клиентское приложение
    3. Админка
    4. Мобильные приложения

    Потратьте время на пользовательские истории, UML диаграммы и схемы интерфейсов. Используйте трекер задач.

    Мое мнение, чтобы изучить все вышеперечисленное, а начинать вам, судя по всему, придется начать с основ JavaScript, HTML и CSS, уйдет уйма времени. Чтобы после изучения всего вышеперечисленного, научиться на всем этом писать хороший код, уйдет еще больше времени. Одно дело изучить инструменты, совсем другое научиться писать хороший код, решать типовые задачи, организовывать архитектуру. А решать задачи всех планов, вам придется как по фронтенду, так и по бекенду.

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

    Если на рынке уже есть сильный конкурент и ваш сервис просто будет повторять его бизнес модель, то он вряд ли взлетит, только потратите силы и время. Обязательно изучите рынок прежде чем, что-либо предпринимать.
    Ответ написан
    2 комментария
  • В массиве меняется весь массив с объектами?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Вы передаете ссылку на один и тот же массив всем элементам массива graffik:
    grafik.forEach(elem => {
      elem.attr = attr; 
    });


    Когда передаете напрямую, срабатывает именно потому, что каждый раз создаете новый массив с новыми объектами.

    Вам надо передавать копии массива с копиями вложенных объектов. Сделать это можно так:
    grafik.forEach(elem => {
      elem.attr = attr.map(el => ({ ...el }));
    });

    Либо, если не используете spread оператор:
    grafik.forEach(elem => {
      elem.attr = attr.map(el => Object.assign({}, el));
    });
    Ответ написан
    2 комментария
  • Почему объект не ссылается сам на себя?

    rockon404
    @rockon404
    Frontend Developer
    Изначально переменной list присваивается значение null. Дале, каждую итерацию выполняется код:
    list = { value: array[i], rest: list };
    Сначала выполняется правая часть выражения, создается объект со свойством value принимающим значение элемента массива по индексу i, и свойством rest принимающим значение list, первую итерацию оно null:
    { value: 10: rest: null };
    Ну, а затем созданный объект присваивается переменной list. И так каждую итерацию.

    Простой пример как это работает:
    var x = 10;
    
    x = x + 5;

    Сначала вычисляется правая часть, затем происходит присваивание:
    x = 10 + 5;
    или:
    x = 15;

    А так можно сделать ссылку на себя:
    var obj = {       // создаем объект доступный по ссылке obj
      prop: 'example prop' 
    };
    
    obj.self = obj;  // добавляем в объект свойство self ссылающееся на сам объект
    Ответ написан
    1 комментарий
  • Почему побитовые операторы не работают?

    rockon404
    @rockon404
    Frontend Developer
    У вас две опечатки. Объявленны summidle и sum, а используются sumidle и summ.
    Учитесь анализировать ход выполнения кода и отлаживать его в консоли браузера.
    Лучше использовать логическое && и строгое сравнение:
    var summidle = 3;
    var sum = 16;
    
    if (summidle === 3 && sum > 11 && sum < 22){
      alert("legend");	
    }
    Ответ написан
    Комментировать
  • Почему не получается подключить обработку клавиатурного ввода?

    rockon404
    @rockon404
    Frontend Developer
    В вашем коде нигде не вешается слушатель на событие ввода.
    Еще очень плохой тон, тащить в JS и CSS стиль форматирования С++/C#.
    Ответ написан
    5 комментариев
  • Что делает оператор new?

    rockon404
    @rockon404
    Frontend Developer
    Добавлю к вышенаписанному, что работу оператора new можно симитировать следующей функцией:
    function newExpression(constructor) {
      if ( typeof constructor !== 'function') {
        throw new TypeError(constructor + 'is not a constructor');
      }
    
      var args = Array.prototype.slice.call(arguments, 1);
      var obj = Object.create(constructor.prototype);
      
      return constructor.apply(obj, args) || obj;
    }

    Демо.
    В отличии такой имитации настоящий оператор new успешно создаст экземпляр даже по забинженому на другой контекст конструктору (по факту, возвращенной привязанной функции), так как оператор new игнорирует преданное значение this. Аргументы же будут применены из [[BoundArguments]]:
    var User = function(name) {
      this.name = name;
    }
    
    User.prototype.getName = function() {
      return this.name;
    }
    
    const obj = {};
    
    User = User.bind(obj, "Sarah");
    
    var john = new User('John');
    
    console.log(john.getName()); // 'Sarah'


    Спецификации new и [[Construct]]
    Ответ написан
    Комментировать
  • При одалживании метода объект живет или выпиливается?

    rockon404
    @rockon404
    Frontend Developer
    Во-первых вы не отдалживаете метод, а получаете на него ссылку. Во-вторых ссылка на метод, в вашем случае, находится не в самом объекте, а является свойством прототипа. В-третьих в JavaScript объекты удаляются по принципу достижимости. Если на объект нет ни одной ссылки, то занимаемая им память будет очищена при первой же возможности. Если же на объект есть ссылки, то это еще не гарантия, что память не будет очищена.
    Например:
    let foo = {};
    let bar = {};
    foo.barLink = bar;
    bar.fooLink = foo;
    
    foo = bar = null;


    На объекты есть ссылки barLink и fooLink, но они недостижимы, ведь мы не можем обратиться к этим свойствам, после того как переназначили переменные foo и bar,. Поэтому память занимаемая объектами будет очищена, несмотря на наличие ссылок.

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

    Другое дело, если мы сначала забиндим метод на наш объект:
    class Person {
      constructor(name) {
        this.name = name;
      }
      printName() {
        console.log(this.name);
      }
    }
    
    let john = new Person('John');
    const obj = {};
    
    obj.printJohnName = john.printName.bind(john);
    john = null;
    
    obj.printJohnName();  // 'John'

    Объект ранее доступный по ссылке john не будет удален, так как мы забиндили на него функцию и в ней есть скрытое свойство [[BoundThis]], ссылающееся на него:
    5a84af46ab784660788834.png
    Ответ написан
    Комментировать
  • Как создать такой массив с данными?

    rockon404
    @rockon404
    Frontend Developer
    const map = {};
    
    srcArray.forEach(({ title, value }) => {
      map[title] = map[title] || { title, data: [] };
      map[title].data.push({ money: value });
    });
    
    const resultArray = Object.values(map);
    Ответ написан
    2 комментария
  • Почему не вешается обработчик на react компонент?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    А с чего вы взяли что он там должен быть? Вам, думаю, стоит подтянуть основы JavaScript.

    Если используете синтаксис ES6, используйте импорты и экспорты:
    import React from 'react';

    export default Task;

    Хандлеры лучше биндить не в render, а в конструкторе:
    constructor(props) {
      super(props);
    
      this.state = {
        isOpened: false,
      };
    
      this.clickHandler = this.clickHandler.bind(this);
    }


    Или определяйте хандлер как class field arrow function:
    clickHandler = e => {
      // your stuff
    };

    Такая функция привязана к контексту экземпляра и биндить ее не надо.
    create-react-app поддерживает такой синтаксис из коробки.

    Нельзя передавать текущее состояние в метод setState, так как это асинхронный метод, к моменту вызова состояние может успеть измениться и будет использовано старое значение. Чтобы обновить состояние на основе предыдущего передавайте в setState функцию возвращающую объект. При вызове, первым аргументом в нее придет актуальное состояние на момент обновления:
    this.setState(prevState => ({
      isOpened: !prevState.isOpened,
    }));


    Вместо var используйте const для неизменяемых значений и let для изменяемых.

    Наконец, следите за чистотой кода. Вот хорошие гайдлайны от Airbnb:
    Гайдлайн Airbnb по JavaScript
    Гайдлайн Airbnb по React
    Ответ написан
    6 комментариев
  • Как узнать сколько времени осталось до срабатывания таймера?

    rockon404
    @rockon404
    Frontend Developer
    Можно так:
    var duration = 32 * 60 * 1000;
    var step = 1000;
    var endsAfter = duration;
    
    var timer = setTimeout(alert, duration, 'Hello world!');
    
    var interval = setInterval(function() {
      endsAfter -= step;
      if (endsAfter <= 0) clearInterval(interval);
      console.log('Timeout через: ', endsAfter);
    }, step);

    Демо
    Ответ написан
    Комментировать
  • Почему props меняется сразу для всех, а не для каждого отдельно, react/redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Можно сделать isLoading и хранилище сущностей объектом:
    const initialState: {
      entities: {}.
      isLoading: {
        'ALL': false, 
      },
       isError: {
        'ALL': false, 
      }
    }


    const someEntityReduser = (state = initalState, action) => {
      const { type, payload } = action;
    
      switch (type) {
        case GET_ALL_ENTITIES_REQUEST:
          return {
            ...state,
            isLoading: {
              ...state.isLoading,
              'ALL': true, 
            },
            isError: {
              ...state.isError,
              'ALL': false, 
            },
          };
    
        case GET_ALL_ENTITIES_SUCCESS:
          return {
            ...state,
            entities: payload,  // либо нормализация если приходят массивом
            isLoading: {
              ...state.isLoading,
             'ALL': false,
            },
          };
    
        case UPDATE_ENTITY_REQUEST:
          return {
            ...state,
            isLoading: {
              ...state.isLoading,
              [payload.id]: true, 
            },
            isError: {
              ...state.isError,
              [payload.id]: false, 
            },
          };
          
        case UPDATE_ENTITY_SUCCESS:
          return {
            ...state,
            entities: {
               ...state.entities,
               [payload.id]: payload,  
            },
            isLoading: {
              ...state.isLoading,
              [payload.id]: false,
            },
          };
        
         /* other cases */
      }
    }
    Ответ написан
  • Адекватный ли конструктор?

    rockon404
    @rockon404
    Frontend Developer
    Не понимаю назначения этой сущности, но это не конструктор. Метод viewer назван неправильно, так как название не говорит ничего о том, что этот метод делает.
    Конструкгор это когда так:
    spoiler
    function SetUserManager(config) {
      this.client = new ClientUser();
      this.clientManager = new ClientManager({
        user: this.client
      });
    
      this.options = {
        name: config.name,
        key: config.key
      };
    
      this.cookies = [];
    
      client.login(options);
      this.viewer();
    }
    
    SetUserMagager.prototype.viewer = function() {
      this.client.on('login', () => {
        this.client.setLogin();
      });
    
      this.client.on('msg', (session) => {
        serveSession(session);
      });
    
      this.clientManager.on('user', (data) => {
        serveNewUser(data);
      });
    }

    или так:
    spoiler
    class SetUserMagager {
      constructor(config) {
        this.client = new ClientUser();
        this.clientManager = new ClientManager({
          user: this.client
        });
    
        this.options = {
          name: config.name,
          key: config.key
        };
    
        this.cookies = [];
    
        client.login(options);
        this.viewer();
      }
      
      viewer() {
        this.client.on('login', () => {
          this.client.setLogin();
        });
    
        this.client.on('msg', (session) => {
        	serveSession(session);
        });
    
        this.clientManager.on('user', (data) => {
          serveNewUser(data);
        });
      }
    }

    Складывается впечатление, что вы везде пытаетесь использовать ООП и плодите сущности там, где они не нужны и где лучше использовать функциональный стиль.

    Насчет ваших обработчиков ничего не скажешь так как не ясно, ни что такое ClientUser и ни что такое ClientUserManager.
    Ответ написан
    2 комментария
  • Как вернуть значени из модуля из асинхроной функции?

    rockon404
    @rockon404
    Frontend Developer
    Если вы хотели вернуть результат из person то так:
    module.exports.person = async () => await sqlQuery();

    Другое дело, что async/await тут и не нужны.
    Их использование было бы оправдано сели бы надо было сделать что-то вроде:
    module.exports.person = async () => [await sqlQuery1(), await sqlQuery2()];

    или:
    module.exports.person = async id => {
      const user = await getUser(id);
      const permissions = await getPermissions(user.role);
     
      return {
        user,
        permissions,
      };
    }

    В вашем случае достаточно:
    module.exports.person = args => sqlQuery(args);
    А использовать уже можно в асинхронных функциях:
    const user = async person(id);
    Ответ написан
    Комментировать