Ответы пользователя по тегу JavaScript
  • Как работает Array.prototype.slice.call?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Это один из способов преобразовать массиво-подобные HTMLCollection или Nodelist в настоящий массив со всеми его методами для последующей работы.

    Другой вариант сделать то же самое, с современным синтаксисом:
    const index = [...this.children];
    Ответ написан
    1 комментарий
  • Как считать RPS, если соединение устанавливается от 0 до 5 секунд?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Запросы имеют протяжённость во времени.
    Начало запроса — отправка запроса клиентом.
    Окончание – завершение получения данных клиентом и закрытие соединения.

    Неизвестно тут, что сервер считает за отметку времени запроса: его начало, конец, или что-то ещё.

    Допустим, разрешены 3 запроса в 1 секунду.
    Отправил 3 одновременно. Но 2 из них призадумались и тянутся по 5 секунд каждый, а один отыграл за 500 миллисекунд. Когда можно отправить ближайший следующий запрос?
    |--------------------|
    |--------------------|
    |--|
    0-----1-----2-----3--

    Гарантированно можно через 1 секунду после завершения 3-го быстрого, т.е. через 1500мс со «старта».

    И можно эвристически порисковать и чуть уменьшить эту паузу с окончания очередного запроса.

    Можно держать N «дорожек» – по числу одновременных запросов в единицу времени. И ставить очередной запрос на первую освободившуюся «дорожку».
    Ответ написан
    Комментировать
  • Как объединить несколько функций JS?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Исходный код можно примерно так отрефакторить. Вынести в аргументы то, что меняется:
    function addBehavior(idFrom, idTo, isChangingHeight) {
      const elFrom = document.getElementById(idFrom);
      const elTo = document.getElementById(idTo);
      
      const onOut = () => {
        elTo.style.width = "";
        isChangingHeight  &&  elTo.style.height = "";
    //    elFrom.removeEventListener(onOut);
      }
      
      const onOver = () => {
        elTo.style.width = "50%";
        isChangingHeight  &&  elTo.style.height = "50%";
    //     elFrom.removeEventListener(onOver);
      }
      
      elFrom.addEventListener("mouseover", onOver);  
      elFrom.addEventListener("mouseout", onOut);
    }
    
    addBehavior('gg', 'bg', true);
    addBehavior('zz', 'qq');

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

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    id обязательно должны быть уникальными. Нельзя использовать один id для нескольких элементов.

    Зато className может присутствовать у многих элементов. Назначьте всем слайдам класс slide-item

    Upd. примерно так можно, коротко и просто:
    Ответ написан
  • Как управлять запросами к API на клиенте?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Писать свой или искать готовый механизм очереди с контролем времени.

    В очередь (массив) класть запрос (метод, параметры) и callback. Либо промисы.

    Держать массив с временем ответов последних 100 (30) вызовов. Если самый древний более 10 (5) секунд назад, можно выполнить очередной.

    Как-то написал вот такую
    кривую реализацию


    Модуль очереди:
    /**
     * Hold Your Horses!
     * Promise-based dispatcher that respects frequency limits.
     * It queues requests so that no more than N are processed within 1 second.
     * Those can go in parallel.
     *
     * Instantiate the new HH with options, specifying time limit.
     * Method .add(function) adds a new job to the queue.
     * Argument function should return Promise object that starts to process only after the function is called.
     * @return Object Promise.
     */
    
    function HorsesHolder(options) {
      options         = options || {};
      this.rps        = options.rps || 3; // requests per second
      this.parallel   = options.parallel || this.rps; // max parallel running jobs
    
      this.times      = []; // -1: slot is busy, 0: slot is free, positive timestamp - time slot's job has finished
      for (let i=0; i<this.rps; i++) this.times.push(0); // [0, 0, 0] initially
    
      this.queue      = [];
      this.inprogress = [];
      this.debug      = !!options.debug;
      
      this.debug  &&  console.log("%s ms: [HH] initialized", this.ts());
    }
    
    
    HorsesHolder.prototype.add = function(promiseMaker) {
      var self = this;
      
      return new Promise(function(resolve, reject) {
        self.queue.push({
          resolve: resolve,
          reject: reject,
          promiseMaker: promiseMaker,
        });
        
        self._ping();
      });
    };
    
    
    // Decide: work or wait
    HorsesHolder.prototype._ping = function() {
    
      if (this.queue.length === 0) {
        this.debug  &&  console.log("%s ms: [ping] queue is empty", this.ts());
        return;
      }
      
      const best = this._bestTime();
      
      if (best === -1) {
        this.debug  &&  console.log("%s ms: [ping] cannot go: %s", this.ts(), JSON.stringify(this.times));
        return;
      }
      
      const index = this.times.indexOf(best);
      
      this.debug  &&  console.info("%s ms: [ping] exec now at index %d", this.ts(), index);
    
      this._execute(index);
    }
    
    
    /**
     * Out of current times[] finds the best to occupy, if possible;
     * otherwise -1
     */
    HorsesHolder.prototype._bestTime = function() {
      let best = -1;
    
      for (let i=0; i<this.rps; i++) {
        const time = this.times[i];
        if (time === 0) return 0;        // can go now - nothing better!
        if (time < 0) continue;          // previous not finished yet
        if (this.ts() < time + 1000) continue; // not yet
    
        if (best === -1) best = time;
        else best = Math.min(best, time);
      }
      
      return best;
    }
    
    
    HorsesHolder.prototype.ts = function() {
      return (new Date()).getTime();
    }
    
    
    HorsesHolder.prototype._execute = function(index) {
      this.times[index] = -1; // mark busy
      const job = this.queue.shift();
      this.inprogress.push(job);
    
      const self = this;
      
      job.promiseMaker()
      .then(function(r) {
        self.debug  &&  console.info("%s ms: [HH] Job done at index %d", self.ts(), index);
        job.resolve(r);
      })
      .catch(function(err){
        self.debug  &&  console.error("%s ms: [HH err] Error at index %d: %s", self.ts(), index, err.toString());
        job.reject(err);
      })
      .finally(function(){
        self.inprogress.splice( self.inprogress.indexOf(job), 1);
        self.times[index] = self.ts();
        setTimeout(() => self._ping(), 1000);
      });
    }
    
    export default HorsesHolder;


    Модуль работы с VK API:
    /*global VK*/
    /**
     * Function returns Promise for each VK API call.
     * Respects the 3 call per second limit.
     *
     * by Sergei Sokolov <hello@sergeisokolov.com> 2019.
     */
     
    import HorsesHolder from '@/utils/horsesholder';
    
    const debug = true;
    
    const HH = new HorsesHolder({ debug });
    
    
    export default function asyncVK(methodName, data) {
    
    	return HH.add(() => {
    
    		data = data || {};
    		if (!data.v) data.v = 5.92; // VK API version https://vk.com/dev/versions
    		
    		return new Promise((res, rej) => {
    			VK.Api.call(
    				methodName,
    				data,
    				r => {
    					if (r.error) {
    						debug && console.error("[asyncvk] VK API call error:", r.error);
    					}
    					
    					
    					if (r.response) {
    						
    						res(r.response);
    						
    					} else if (r.error) {
    						
    						rej(r.error);
    						
    					} else {
    						
    						debug && console.error("[asyncvk] VK API bad response:", r);
    						
    						rej(r);
    						
    					}
    				}
    			)
    		});
    	});
    }


    Ответ написан
    1 комментарий
  • Почему не выводятся на экран числа массива с помощью цикла for?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    первый вариант:

    var mass = [1,2,3,4,5,6,7,8,9,10];
    for(i=0;i<mass.length;i++){
        document.getElementById('root').innerHTML += mass[i];
    }


    второй вариант:

    var r = document.getElementById('root');
    var mass = [1,2,3,4,5,6,7,8,9,10];
    for(i=0;i<mass.length;i++){
        r.innerHTML += mass[i];
    }


    Но разумеется можно короче
    var mass = [1,2,3,4,5,6,7,8,9,10];
    for (document.getElementById("root").innerHTML = mass.join(","); 0;)
    Ответ написан
    Комментировать
  • Возможно ли при клике сэмулировать двойнок клик?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Ваниль:
    document.getElementById("tot-block")
      .addEventListener("click", e => e.target.dispatchEvent(
        new MouseEvent('dblclick', {
          'view': window,
          'bubbles': true,
          'cancelable': true
        })
      )
    );


    ⚠️ Любое событие, сгенерированное скриптом, отличается от «честного» действия пользователя свойством события isTrusted.
    Ответ написан
    Комментировать
  • Какие есть способы округлить число на js?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    const roundigit = digit => {
      if (1!==digit.toString().length||!Number.isFinite(digit))throw "Не цифра!";return digit;}

    spoiler
    Цифра - это 0, 1,2,3,4,5,6,7,8 или 9 - каждая их них целая. Можно не округлять. Расходимся.


    если серьёзно
    Чтобы в сторону нуля округлять, вариант:
    const floor = x => x | 0;
    Ответ написан
    2 комментария
  • VK api. Как получить json всех Олегов из города Кукуева?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Вероятная причина ошибки

    Метод users.get() можно вызывать с ключом одного из трёх типов:
    • сервисный ключ (приложения)
    • ключ сообщества
    • ключ пользователя
    в то время, как users.search() можно вызывать только с ключом пользователя.

    Раз users.get() срабатывает , а на users.search() возвращается ошибка токена, вероятнее всего используется токен Сообщества или Сервисный ключ приложения.

    Что делать

    Получите ключ Пользователя. Для этого понадобится создать своё приложение ВК или использовать уже готовое. Специальных прав запрашивать не нужно, просто получить токен.

    В запросе к users.search() для поиска только в городе N, понадобится найти сначала id этого города N в Справочнике городов ВК. Для этого есть метод database.getCities() - клик по ссылке (внизу страницы) выполнит поиск и вернет несколько населенных пунктов, похожих на «Кукуево», у каждого свой id.

    Итого, в метод users.search() вы передадите следующие параметры:
    1. v=5.101 — версия API, обязательный
    2. access_token=XXXXX — токен Пользователя в любом приложении ВК
    3. count=1000 — без этого параметра вернёт только 20 результатов
    4. q=Олег — поисковая строка
    5. city=123 — id города Кукуево, полученный ранее в database.getCities()
    6. sex=2 — мужской пол (необязательно)
    7. age_from=18 — искомый Олег закончил школу
    8. age_to=24 — наверное, искомый Олег ещё не получает пенсию
    Ответ написан
    3 комментария
  • Как использовать строковые методы и выведите "tetsetesesesesteest"?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Строку собирайте по частям. Пригодятся эти семь методов объекта String:
    Примените каждый из них, чтобы получить часть результата.

    Например, так
    const x = "test";
    const result = ''
      + x.substr(0, 2) // te
      + x.split('').reverse().join('') // tset
      + x.substring(1,3).repeat(4) // eseseses
      + x.substring(0,2) // te
      + x.substring(1)   // est
    ; // tetsetesesesesteest

    Но здесь «незаконно» используется преобразование к Array для отзеркаливания строки "test" -> "tset".

    Задача творческая и довольно забавная. Проявите себя и найдите какой-то оригинальный способ.
    Ответ написан
    Комментировать
  • Как передать индекс цикла внутрь него другому массиву?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    К изучению: замыкания в JS.

    С минимальными изменениями можно примерно так сделать функцию, создающую функции, каждая запоминает переданный i:
    плохой код
    const slides = document.querySelectorAll('.reviews__item');
    var radioButtons = document.getElementsByName('review-toggle');
    var makeListener = function(i) {
      return function (evt) {
        evt.preventDefault;
        for (var j = 0; slides.length > j; j++) {
          slides[j].classList.add('slider__item--hidden');
        };
        slides[i].classList.remove('slider__item--hidden');
      };
    }
    
    for (var i = 0; i < radioButtons.length; i++) {
      radioButtons[i].addEventListener ('click', makeListener(i));
    };


    Лучше так:
    Ответ написан
    Комментировать
  • Удалить лишние знаки?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    const f = n => parseFloat(n.toFixed(5));
    
    // Tests:
    f(1) // 1
    f(1.12) // 1.12
    f(1.1234567890) // 1.12346
    f(000001) // 1
    f(100000) // 100000
    f(-1e5) // -100000


    Upd. Если обязательно именно отбросить без округления, то надо работать как со строками:
    (()=>{
      
    const f = x => {
      const n = parseFloat(+x);
      const sign = Math.sign(n);
      // отсечь экпоненциальную запись (0.0000001).toString() === "1e-7"
      if (Math.abs(n) < 1e-5) return 0; 
      return sign * parseFloat(x)
        .toString()
        .split('.')
        .map((n,i) => i ? n.substring(0,5) : parseInt(n))
        .join('.');
    }
    
    // Tests:
    ['0000001', '0.0000101', 1.000000001,  -1e-4, -1e-5, -1e-6, 1e5, Math.E, 1, -1, 0, false, ]
      .map(n => `${n} // ${f(n)}`)
      .join('\n');
    /*
    0000001 // 1
    0.0000101 // 0.00001
    1.000000001 // 1
    -0.0001 // -0.0001
    -0.00001 // -0.00001
    -0.000001 // 0
    100000 // 100000
    2.718281828459045 // 2.71828
    1 // 1
    -1 // 1
    0 // 0
    false // 0
    */
    Ответ написан
  • Как выполнить JS код после загрузки страницы?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    См. подробнее про загрузку скриптов с async и defer

    // вызовет initialize только когда догрузятся все скрипты defer:
    document.addEventListener('DOMContentLoaded', initialize);
    Ответ написан
    1 комментарий
  • Что такое коллекция в JavaScript?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Четкого определения «collection» в JavaScript не встречал. Интуитивно, коллекция это структура данных для хранения нескольких значений.

    Объект и массив, по-моему, можно отнести к коллекциям.

    В ES6 появились два новых типа данных – Map и Set, которые тоже можно отнести к «коллекциям». В переводе на Русский язык словом «Коллекция» назвали из них именно Set, предназначенный для хранения только уникальных значений. Но я бы не считал требование уникальности значений отличительным признаком «коллекций» вообще.
    Ответ написан
    2 комментария
  • Что значит .chance?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    chance – новое придуманное свойство объекта request, назначаемое ему обработчиком.

    Пришёл запрос. Ему навесили новое свойство chance, записав в него случайное число от 0 до 1.
    В ответ на GET-запрос возвращают JSON, описывающий объект с единственным свойством тоже под названием "chance" (шанс), со значением взятым из ранее назначенного свойства объекта запроса.

    Свойство можно назвать как угодно. Например, toster. Тогда код выглядел бы так (замена в двух местах), но функционировал точно так же; возвращал тот же самый формат ответа:
    код
    const express = require('express')
    const app = express()
    app.use((request, response, next) => {  //Промежуточный обработчик
        console.log(request.headers)
        next()
    })
    app.use((request, response, next) => {
        request.toster = Math.random()
        next()
    })
    app.get('/', (request, response) => {
        response.json({
            chance: request.toster
        })
    })
    app.listen(3000)


    .headers — свойство объекта запроса, наследованное от нативного Node'овского объекта запроса, см. http.IncomingMessage.headers. Содержит все HTTP-заголовки принятого HTTP запроса.
    Ответ написан
    Комментировать
  • Как преобразовать массив из 64 чисел от 0 до 63 в цвет?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Тут некоторая избыточность.
    Цвет в вебе задаётся одним байтом 0..FF (0..255) для каждого компонента: R, G, B и, опционально, альфа (прозрачность 0..100). Прозрачность, вероятно, отбросим.
    Будем считать, что цвет – это три байта = 24 бита.

    0..63 это 6 бит. Для цвета достаточно четырёх чисел 0..63, чтобы получить 4 * 6 = 24 бита.
    четыре 6-битовых дают три 8-битных:
    00000011 11112222 22333333


    В массиве из 64 элементов 64 / 4 = 16 таких четвёрок, или 16 цветов. Можно генерить градиент )

    Вариант решения
    (()=>{
      // из четырёх чисел 0..63 получить строку цвета типа "#abcdef"
      const makeColor = (n1, n2, n3, n4) => {
        const r = (n1 & 63) << 2 | (n2 & 48) >> 4;
        const g = (n2 & 15) << 4 | (n3 & 60) >> 2;
        const b = (n3 & 3) << 6 | n4 & 63;
        return '#' + [r,g,b].map(n => n.toString(16).padStart(2,'0')).join('');
      }
      
      // из массива чисел от 0 до 63, длиной кратной 4, получить массив цветов
      const arrToColor = arr => {
        const len = arr.length;
        if (len % 4) throw "Длина массива не кратна 4";
    
        const result = [];
        for (let i=0; i<len; i+=4)
          result.push(makeColor(...arr.slice(i, i+4)));
    
        return result;
      }  
    
      // тест
      const test = () => arrToColor(
        [...new Array(64)].map(()=>Math.floor(64 * Math.random()))
      );
      return test();
    })()
    
    /*
    #941510,#4b31ca,#eec8c9,#4c9202,
    #336a01,#95b7ec,#e73d44,#4069e6,
    #4d1700,#8efa27,#8e0333,#f089af,
    #67b561,#fc8fc8,#48503c,#f308a9
    */


    Ответ написан
    Комментировать
  • Можно ли упростить функцию?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Можно расставлять имена класса строкам таблицы, относящимся к одной из опций селекта. Выбрали в селекте опцию, спрятали все строки, показали только строки с известным именем класса.

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

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    1. дайте какой-то уникальный id тому div'у рядом с "Результат"
    2. получите этот div, как вы уже делаете с "chislo1": var div = document.getElementById(...
    3. вставьте в него результат: div.innerText = "вот, что получилось";
    Ответ написан
    3 комментария
  • Как выполнить код после перезагрузки страницы?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Пусть форма отправляет данные POST'ом на главную.
    Сервер, получив данные, пусть включает в код страницы js, который хотите выполнить.
    Ответ написан