Ответы пользователя по тегу JavaScript
  • Как разбить js на файлы/модули?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Совершенно не понимаю зачем городить огород с оборачиванием в функцию предложенный Александр Косицын . Этот способ скорее подходит для модулей написанных для браузера, с целью изолировать их пространство имен.
    Предлагаю не заморачиваться, и поступить так, как показано в оф.доке express-а:
    файл с кодом роутера
    var express = require('express');
    var router = express.Router();
    
    // middleware that is specific to this router
    router.use(function timeLog(req, res, next) {
      console.log('Time: ', Date.now());
      next();
    });
    // define the home page route
    router.get('/', function(req, res) {
      res.send('Birds home page');
    });
    // define the about route
    router.get('/about', function(req, res) {
      res.send('About birds');
    });
    
    module.exports = router;
    основной файл приложения
    ...
    var birds = require('./birds');
    ...
    app.use('/birds', birds);
    ...



    PS: при этом имена и местоположение файлов роутеров весьма условная вещь. По факту вы можете давать им любые имена и укладывать в любые папки, главное не запутайтесь при их подключении. Например некий роутер отвечающий за чат лежит в папке `/routers/chat` и называется `main.js`. Чтобы его подключить, нам надо будет написать что то типа:
    ...
    var chat = require('./routers/chat/main.js');
    ...
    app.use('/chat, chat);
    ...
    Ответ написан
    2 комментария
  • Возможно ли решить задачу без циклов?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Еще 1 вариант с рекурсией (правда он уничтожает исходный массив):
    function sum(arr) {
    	var val = arr.pop();
    	if( !val ) return 0;
    	if( Array.isArray(val)) return sum(val)  + sum(arr);
    	return val + sum(arr);
    }

    демка:


    PS: так же провел тесты:
    код
    let array = [];
    
    // так как sum_2 уничтожает исходный массив, для адекватности 
    // добавил переинициализацию массива исходных данных
    
    
    
    function sum_1(arr) {
    	if (!arr.length) {
    		return 0;
    	}
    	let val = arr[0];
    	if (val instanceof Array) {
    		val = sum_1(val);
    	}
    	return val + sum_1(arr.slice(1));
    }
    
    
    function sum_2(arr) {
    	var val = arr.pop();
    	if (!val) return 0;
    	if (Array.isArray(val)) return sum_2(val) + sum_2(arr);
    	return val + sum_2(arr);
    }
    
    console.time('init array');
    for (let i = 0; i < 1000; i++) {
    	array = [
    		[1, 4],
    		[11],
    		[3, 5, 7]
    	];
    }
    console.timeEnd('init array');
    
    console.time('eval');
    for (let i = 0; i < 1000; i++) {
    	array = [
    		[1, 4],
    		[11],
    		[3, 5, 7]
    	];
    	eval(JSON.stringify(array).replace(/[^\d]+/g, '+') + '0') // 31
    }
    console.timeEnd('eval');
    
    console.time('sum recursion 1');
    for (let i = 0; i < 1000; i++) {
    	array = [
    		[1, 4],
    		[11],
    		[3, 5, 7]
    	];
    	sum_1(array);
    }
    console.timeEnd('sum recursion 1');
    
    
    console.time('sum normal');
    for (let i = 0; i < 1000; i++) {
    	array = [
    		[1, 4],
    		[11],
    		[3, 5, 7]
    	];
    	[].concat.apply([], array).reduce(function(res, item) {
    		return res + item;
    	})
    }
    console.timeEnd('sum normal');
    
    
    
    console.time('sum recursion 2');
    for (let i = 0; i < 1000; i++) {
    	array = [
    		[1, 4],
    		[11],
    		[3, 5, 7]
    	];
    	sum_2(array);
    }
    console.timeEnd('sum recursion 2');


    init array: 0.615ms
    eval: 6.717ms
    sum recursion 1: 6.927ms
    sum normal: 1.921ms
    sum recursion 2: 3.753ms

    из которых видно что второй вариант рекурсии достаточно быстрый
    Ответ написан
    Комментировать
  • Для чего var elem = options.elem; и и в чем разница и для чего в 31 строке файла JS change, и "index.html" addEventListener('change')?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Уважаемая olya_097, в представленном Вами коде нет почти ничего из заданных вопросов (1 - нет, 3-нет, 4.нет)
    попробую потелепатить, скорее всего речь идет о событийной модели браузера, и ответы вы найдете тут:
    1. телепатия мне не помогла
    2. подробно тут
    3.
    - bubbles: true - подробно тут
    - detail: +vote - по всей видимости увеличение счетчика голосования
    4. подробно тут


    PS: был не прав :)

    Павло Пономаренко, да действительно, не увидел
    olya_097, был невнимателен, примите в качестве извинения за мой наезд:

    /**
     * функция реализует логику "компонента" voter. Используется так:
     *   var voter = new Voter({
     *     elem: document.getElementById('voter')
     *   });
     * @param {object} options объект с параметрами, может содержать ключи
     *                         - elem ссылка на html элемент, содержащий в
     *                           себе кнопки уменьшения (html элемент с css 
     *                           классом class="down") и увеличения (html 
     *                           элемент с css классом class="up") а также 
     *                           элемент отображения текущего состояние (html 
     *                           элемент с css классом class="vote")
     * 
     */
    function Voter(options) {
      // делаем ссылку на html элемент короче, чтобы не писать везде options.elem
      var elem = options.elem;
    
      // получаем дочерний элемент '.vote'
      var voteElem = elem.querySelector('.vote');
    
      // устанавливаем для 'компонента' voter обработчик события 'click'
      elem.onclick = function(event) {
        if (event.target.closest('.down')) {
          // если клик был по дочернему элементу '.down'
          voteDecrease();
        } else if (event.target.closest('.up')) {
          // если клик был по дочернему элементу '.up'
          voteIncrease();
        }
      }
    
      // устанавливаем для 'компонента' voter обработчик события 'onmousedown'
      elem.onmousedown = function() {
        return false;
      };
    
      // ----------- методы -------------
    
      // функция уменьшает значение в дочернем элементе '.vote' на единицу
      function voteDecrease() {
        setVote(+voteElem.innerHTML - 1);
        // где:
        // +voteElem.innerHTML - приведение строки voteElem.innerHTML к числу
        // +1 - добавляем 1 :)
      }
    
      // функция увеличивает значение в дочернем элементе '.vote' на единицу
      function voteIncrease() {
        setVote(+voteElem.innerHTML + 1);
        // где:
        // +voteElem.innerHTML - приведение строки voteElem.innerHTML к числу
        // +1 - добавляем 1 :)
      }
    
      // функция устанавливает дочернему элементу '.vote' значение равное
      // числу, переданному в параметре vote
      function setVote(vote) {
        voteElem.innerHTML = +vote;
        
        
        // создаем кастомный объект содержащий данные о событии
        var widgetEvent = new CustomEvent(
          // указываем имя кастомного событие "change". 
          "change", 
          // передав в качестве параметровнего данные о событии
          {
            bubbles: true, // тут расписано https://learn.javascript.ru/event-bubbling#vsplytie
            detail: +vote  // поле detail кастомного объекта события widgetEvent. Содержит текущее значение счетчика (+vote приводит значение vote к числу)
    
          }
        );
        // инициируем (вызываем) у "компонента" voter созданное событие "change"
        // c параметром detail содержащим установленное количество голосов
        elem.dispatchEvent(widgetEvent);
        // данное событие в данном конкретном случае мы ловим в index.html:
        // document.getElementById('voter').addEventListener('change', function(e) {
        //   alert(e.detail);
        // });
      };
    
      // экспортируем функцию setVote в глобальное пространство имен
      this.setVote = setVote;
    }
    Ответ написан
  • Почему NaN в строке?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    у вас в функции FinalF после text.value.replace(...) остаются пробелы в строке
    замените replace



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


    ЗЫ: исправил ошибки)
    Ответ написан
    2 комментария
  • Как вызвать функцию без одного аргумента?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Если foo всегда принимает 3 или меньше аргументов, при этом соблюдается условие: -если аргументов 2, то это a и c
    то вариант решения, не зависящий от типов переменных может быть таким:

    function foo(a, b, c) {
    	if (arguments.length === 2) {
    		c = b;
    		b = undefined;
    	}
    	// ...
           console.log(a,b,c);
    }
    foo("Ivan", "Ivanov", "Ivanovich");
    foo("Ivan", "Ivanovich");
    Ответ написан
    Комментировать
  • Как модернизировать ф-цию, чтобы она искала целы слова?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Может быть так?


    если же вам нужно четкое соответствие слов (то есть "остров" равен "остров" но не равен "острова") то решение будет таким:
    Ответ написан
    6 комментариев
  • Как вывести результат js скрипта?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Как то так наверное:


    PS: сумму аванса и зарплаты считать не стал, потому в этих колонках нули. Уверен с этим Вы вполне справитесь сами :)
    Ответ написан
  • Какую БД выбрать для Electron-приложения?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    для реляционной БД - SQLite
    для NOSQL БД - nedb (хабр. nedb полностью встраиваемая в приложение, почти в полном объеме реализует систему запросов как в mongodb)
    Ответ написан
    Комментировать
  • Определить самое длинное число в строке?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    2 комментария
  • Как найти общие подстроки в нескольких строках на JavaScript?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Есть более простое (алгоритмически) решение.
    Общая суть его такова, вместо построения матрицы N1 x N2 делаем последовательный сдвиг меньшей строки относительно большей (1 цикл длинной N1+N2-2). На каждой итерации этого сдвига делаем второй цикл через текущую область пересечения этих строк, подсчитывая совпадения символов и запоминая их, если число совпадений больше предыдущего. Так же время выполнения такого алгоритма будет не O(Nmax*Nmin) а O(Nmax*Nmin -Nmin)

    Если не поленюсь, оформлю с утра в виде кода)

    PS: Заставляете не полениться:) Для поддержки поиска по строкам в количестве больше 2-х алгоритм был несколько модифицирован. Для удобства понимания почти не использовал "особые фишки" JavaScript-а, все выполнено на обычных циклах.
    код с комментариями

    function search_largest_substr(){
    	/*
    	Наибольшая общая строка не может 
    	быть больше наименьшей входной строки.
    	Находим наименьшую и по ходу формируем
    	массив с остальными:
    	*/
    
    		// в эту переменную внесем самую маленькую подстроку
    		let str_min = arguments[0];
    		// сюда сложим все остальные подстроки
    		const list = [];
    		
    		// пробежим в цикле по всем переданным в функцию аргументам
    		for(let n=1; n<arguments.length; n++){
    			// если строка в str_min меньше чем в
    			if(str_min.length<arguments[n].length){
    				// вносим в list текущую строку
    				list.push(arguments[n]);
    				// переходим к следующей итерации цикла
    				continue;
    			}
    
    			// иначе в list строку, лежащую в str_min
    			list.push(str_min);
    			// запоминаем в str_min текущую строку
    			str_min = arguments[n];
    		}
    
    	/*
    	Далее нам надо проверить наличие всех возможных
    	подстрок из самой маленькой строки в других строках.
    	Например если самая маленькая подствока была "abcd"
    	то надо последовательно проверить 
    	"abcd", "abc", "bcd", "ab", "bc", "cd", "a", "b", "c", "d"
    	Но при этом, как только будет найдена подстрока имеющаяся
    	во всех строках надо сразу завершить цикл с проверкой.
    	*/
    		// Данный цикл будет определять текущий размер 
    		// проверяемой подстроки, начиная от наибольшего возможного.
    		// Например для строки "abcd" это будут значения 4, 3, 2, 1
    		for(let l=str_min.length; l>0; l--){
    
    			// В данном цикле определяем позицию подстроки.
    			// Например для строки "abcd" это будут значения:
    			// при l=4 будут 0
    			// при l=3 будут 0, 1
    			// при l=2 будут 0, 1, 2
    			// при l=1 будут 0, 1, 2, 3
    			for(let p=0; p<=str_min.length-l; p++){
    				// берем из наименьшей строки тестируемую подстроку
    				const substr = str_min.slice(p, p+l);
    
    				// если искомый фрагмент есть во всех строках
    				// то isFound будет присвоено true
    				let isFound = true;
    
    				// далее в цикле проверяем все остальные строки 
    				// на наличие искомой подстроки
    				for(let i=0; i<list.length; i++){
    					// если искомая подстрока присутствует в
    					// текущей строке - ничего не делаем
    					if(	list[i].indexOf(substr) >= 0)
    						continue;
    
    					// иначе выставляем isFound=false 
    					// и прерываем текущий цикл по i
    					isFound=false;
    					break;
    				}
    
    				// если isFound == true значит нужная подстрока найдена
    				if( isFound )
    					return substr;
    
    				// иначе продолжаем поиск
    			}
    		}
    
    		// если не было найдено ни единой соврадающей подстроки
    		// возвращаем пустую строку
    		return "";
    }
    
    
    // Исползуем функцию поиска так:
    var str = search_largest_substr("ABCDEFGH", "ABCDEFG", "ABCDEF");
    console.log(str);
    
    
    str = search_largest_substr("123445", "12654", "123768");
    console.log(str);


    Ответ написан
  • Как получить id элемента используя addEventListener и getElementsByClassName?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    // получаем массив элементов с именем класса 'slider-nav__dot'
    var dots = document.getElementsByClassName('slider-nav__dot');
    
    // перебираем в цикле все элементы из массива
    for (var i = 0; i < dots.length; i++) {
      // ВНИМАНИЕ!!!!
      // создаем анонимную, само вызывающуюся функцию 
      // в качестве параметра ей передается i
      (function (index) {
        // ВНИМАНИЕ!!!!
        // внутри этой функции переданный ей i уже index. 
        // И если i на всех итерациях это одна и та же переменная с разными значениями
        // то переменная index является самостоятельной переменной, 
        // со своим уникальным значением в каждой итерации цикла 
    
        // создаем функцию-слушатель события "click"  она существует (ее время жизни) 
        // до тех пор пока не будет удалена из слушателей.
        // Внутри нее используется переменная  index объявленная вовне
        // создавая тем самым ЗАМЫКАНИЕ. То есть для каждой итерации цикла
        // переменная index не будет удалена после завершения итерации
        // а будет продолжать жить как замыкание пока жива функция-слушатель ее использующая
        dots[index].addEventListener("click", function () {
          console.log(index);
        })
      })(i);
    
    
    }
    Ответ написан
    Комментировать
  • Полёт пули в игре html5+js?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    ArtC, выкладываю демонстрацию. Покликайте левой кнопкой мышки по листу с сеткой.

    код реализации цикла расчета и отображения пуль
    (function(exports) {
    	console.log("Billets");
    	"use strict";
    
    	/**
    	 * в данном модуле для векторных расчетов используется модуль Vector
    	 * его код доступен по ссылке https://game.lastuniverse.ru/gun.2d.01/js/vector.js
    	 * в этом модуле его функционал доступен через глобальную переменную window.libs.Vector
    	 */
    	// создаем сокращенную ссылку на функционал модуля vector.js
    	const Vector = window.libs.Vector;
    
    
    	/**
    	 * в данном модуле для отрисовки на canvas-е сетки, а также для масштабирования
    	 * используется специальная прослойка. В вашем случае вы будете просто сами рисовать через
    	 * 2d контекст canvas-а полученный с помощью ctx = canvas.getContext("2d");
    	 * здесь же я использую специальные врапперы, таким образом чтобы код 
    	 * представленный далее можно было использовать на обычном контексте canvas-а
    	 */
    	// создаем врапер на контекст канваса canvas.getContext("2d")
    	let ctx = window.libs.ctx;
    	// в вашем случае будет както так
    	// ctx = canvas.getContext("2d");
    
    
    	/**
    	 * Функция перерисовки сетки. В вашем случае это будет функция рисующая 
    	 * через ctx какой то фон на канвасе
    	 */
    	function redraw() {
    		window.libs.sheet.planedReDraw();
    		window.libs.sheet.reDraw();	
    		// в вашем случае будет както так:
    		// ctx.fillStyle="#1b1b1b"; // устанавливаем цвет фона
    		// ctx.fillRect(0,0,canvas.width,canvas.height); // зарисовываем канвас этим цветом
    
    	}
    
    
    	/**
    	 * для того чтобы интерфейс мог иметь доступ к параметрам пули и менять их
    	 * экспортируем объект с настройками и функциями данного модуля. 
    	 * В других модулях будет доступен как window.libs.bullets
    	 * в вашем случае в этом нет необходимости
    	 */
    	exports.bullets = {};
    
    	
    	/**
    	 * Настройки симуляции
    	 * settings.speed 		- скорость новых пуль
    	 * settings.size 		- размер новых пуль
    	 * settings.distance	- радиус жизни пуль
    	 */
    	const settings = {
    		speed: 10,
    		size: 10,
    		distance: 200
    	};
    	// экспортируем для интерфейса объект с настройками пуль. 
    	// В вашем случае в этом нет необходимости
    	exports.bullets.settings = settings;
    	
    
    
    
    
    
    	/**
    	 * Приготовления завершены, начинаем создавать пули !!!!
    	 */
    
    
    
    
    
    	
    	/**
    	 * массив с пулями. каждая пуля описывается объектом, содержащим ключи:
    	 * @key {object} loc 		объект {x: ..., y: ...} содержащий текущие координаты пули
    	 * @key {object} emitter 	объект {x: ..., y: ...} содержащий координаты из которых стартовала пуля
    	 * @key {object} direction 	нормализованный вектор/объект {x: ..., y: ...} содержащий направление полета пули (нормализованный - значит его длинна равна 1)
    	 * @key {number} distance	радиус жизни пули
    	 * @key {number} speed 		скорость пули
    	 * @key {number} size 		размер пули
    	 */
    	let bullets = [];
    
    	
    	/**
    	 * Обработчик собития click по рабочему пространству листа (canvas-а)
    	 * @param  {object} event 	имитация стандартного эвента события click (в вашем случае при использовании этого кода будет не имитация)
    	 */
    	function mouseclick(event){
    		add_bullet(
    			{ x: 0, y: 0 }, // летит из центра
    			{ x: event.clientX, y: event.clientY }, // по направлению к курсору мышки
    			settings.distance, // c радиусом жизни пули указанным в настройках
    			settings.speed, // со скоростью указанной в настройках
    			settings.size // с размером указанным в настройках
    		);
    	}
    	// экспортируем обработчик события click по листу. Будет вызван при клике на листе
    	exports.bullets.mouseclick = mouseclick;
    	// в вашем случае вместо этого вы сделаете так:
    	// canvas.addEventListener("click", mouseclick);
    
    
    	/**
    	 * функция добавления новой пули
    	 * @param {object} emitter 		объект {x: ..., y: ...} содержащий координаты из которых стартует пуля
    	 * @param {object} direction 	        не нормализованный вектор/объект {x: ..., y: ...} содержащий направление полета пули
    	 * @param {number} distance		радиус жизни пули
    	 * @param {number} speed     	скорость пули
    	 * @param {number} size 		размер пули
    	 */
    	function add_bullet(emitter, direction, distance, speed, size) {
    		
    		// заносим в массив с пулями новую пулю
    		bullets.push({
    			emitter: emitter,
    			loc: emitter,
    			direction: new Vector(direction.x, direction.y).normalize(),
    			distance: distance,
    			speed: speed,
    			size: size
    		});
    	}
    
    	/**
    	 * функция расчета следующей позиции пули
    	 * @param  {object} bullet 	объект, содержащий параметры пули: loc, emitter, direction, speed, size
    	 */
    	function calc_bullet(bullet) {
    		
    		// преобразуем координаты в объект класса Vector
    		const loc = new Vector(bullet.loc.x, bullet.loc.y);
    		
    		// рассчитываем вектор приращения в направлении движения пули для ее скорости
    		const vector = bullet.direction.multiply(bullet.speed);
    
    		// добавляем к координатам пули значение вектора с приращениями
    		bullet.loc = loc.add(vector).toLocate();
    	}
    
    	/**
    	 * функция расчета следующей позиции всех пуль.
    	 * также функция следит за удалением пуль при их
    	 * отлете на расстояние превышающее радиус жизни пули
    	 */
    	function calc_all_bullets() {
    		
    		// прокручиваем в цикле все пули
    		bullets.forEach(bullet=>{
    			
    			// расчитываем новые координаты очередной пули
    			calc_bullet(bullet);
    
    			// рассчитываем расстояние пули от точки старта
    			const distance = Math.sqrt( Math.pow(bullet.emitter.x-bullet.loc.x, 2) + Math.pow(bullet.emitter.y-bullet.loc.y, 2) );
    
    			// если дистанция болше чем дистанция жизни этой пули, запоминаем что ее надо удалить
    			if( distance > bullet.distance ){
    				bullet.toDelete = true;
    			}
    		});
    
    		// удаляем помеченые для удаления пули
    		bullets = bullets.filter(bullet=> !bullet.toDelete);
    	}
    
    	/**
    	 * функция отрисовки пули
    	 */
    	function draw_bullet(bullet) {
    		ctx.beginPath();
    		ctx.strokeStyle = "#fff";
    		ctx.fillStyle = "#f00";
    		ctx.arc( bullet.loc.x, bullet.loc.y, bullet.size, 0, Math.PI*2, false );
    		ctx.closePath();
    		ctx.fill();
    		ctx.stroke();		
    	}
    
    	/**
    	 * функция отрисовки всех имеющихся пуль
    	 */
    	function draw_all_bullets() {
    		
    		// прокручиваем в цикле все пули
    		bullets.forEach(bullet=>{
    			
    			// отрисовываем очередную пулю
    			draw_bullet(bullet)
    
    		});
    	}
    
    
    	/**
    	 * функция содержащая действия цикла игровой симуляции
    	 */
    	function play(){
    
    		// следующую строку в вашем случае нужно удалить
    		if(!ctx) ctx = window.libs.ctx;
    
    		// расчитываем новые координаты всех пуль
    		calc_all_bullets();
    
    		// перерисовыаем фон на листе (на канвасе)
    		redraw();
    
    		// перерисовыаем все пули
    		draw_all_bullets();
    
    		// панируем запуск следующей итерации игрового цикла через 20 милисекунд
    		setTimeout(play,20);
    	}
    
    
    	/**
    	 * запускаем функцию игрового цикла.
    	 */
    	play();
    
    })(this.libs=this.libs||{});



    PS: Так же Вы можете дополнительно посмотреть как реализованы векторные вычисления на плоскости canvas-a (вычисление расстояний, скоростей, направлений а также масштабирования) в этом ответе
    Ответ написан
    2 комментария
  • Как правильно написать такой простой скрипт?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    const list = ["Lacquered", "Acrylic", "Veneer", "Laminate", "Thermofused"];
    const row = 13;
    const rowStr = ".from-row:eq(" + row + ")";
    $(rowStr + " .select-change-item option.Lacquered").show();
        $(rowStr + " .select-change-item option:not(.Lacquered)").hide();
        $(rowStr + " .select-change").change(function() {
            list.forEach(item=>{
                if ($(rowStr + " .select-change").val() == item) {
                    $(rowStr + " .select-change-item option."+item).show();
                    $(rowStr + " .select-change-item option:not(."+item+")").hide();
                }
            });
        });
    Ответ написан
    5 комментариев
  • Как добавить на страницу js файл чтобы работал корректно?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    я у себя для подобных целей использую самописный велосипед:

    код модуля (тут можно посмотреть как реализована загрузка других модулей)
    (function(exports) {
    	console.log("Require", exports);
    
    	"use strict";
    
    	// создаем адресное пространство модуля
    	exports.require = load.bind(this);
    
    	/* функция загружает набор произвольных скриптов
    		 options может содержать:
    		 baseurl - адресс сервера на котором находятся скрипты
    							 вида "http://server/"
    							 если не задано берется из window.location
    		 path		- путь к папке со скриптами
    							 вида "your/path/to/scriptd/"
    							 если не задано берется ""
    		 modules - массив с названиями загружаемых скриптов
    							 вида ["script1","script2",...,"scriptN"]
    		 onready - callback функция, вызываемая по завершении загрузки
    							 всех модулей указанных в modules
    	*/
    	function load( options ) {
    		// выход если не указан ни один скрипт для загрузки
    		if( !options.modules )
    			return;
    
    		// если скрипт для загрузки указан в виде строки - переделываем в массив
    		if( typeof options.modules === 'string' )
    			options.modules = [options.modules];
    
    		// выход если скрипты для загрузки не массив
    		if( typeof options.modules != 'object' )
    			return;
    
    		// если не указан URL сервера - берем его из window.location
    		if( !options.baseurl || typeof options.baseurl != 'string')
    			options.baseurl = window.location;
    
    		// если не указан путь к скриптам - берем ""
    		if( !options.path || typeof options.path != 'string')
    			options.path = '';
    
    		// если не указана callback функция - создаем заглушку
    		if( !options.onready || typeof options.onready != 'function')
    			options.onready = function(){};
    
    		// создадим промис, который всегда выполнится
    		var sequence = Promise.resolve();
    
    		// Пройдемся по всем загружаемым модулям (скриптам)
    		for ( let name of options.modules ) {
    			const url =
    					options.baseurl
    				+ options.path
    				+ name;
    
    			// Добавляем действия с ними в конец последовательности
    			sequence = sequence.then( function() {
    				return loadScript( url );
    			} );
    			// .then(function(chapter) {
    			//	 addHtmlToPage(chapter.html);
    			// });
    		}
    
    		sequence.then( function() {
    			// все загрузились
    			options.onready();
    		} );
    
    	}
    
    	/* функция загружает произвольный скрипт по URL и выдает promise */
    	function loadScript( url ) {
    		let promise = new Promise( function( resolve, reject ) {
    			// Adding the script tag to the head as suggested before
    			let head = document.getElementsByTagName( 'head' )[ 0 ];
    			let script = document.createElement( 'script' );
    			script.type = 'text/javascript';
    			script.src = url;
    
    			// Then bind the event to the callback function.
    			// There are several events for cross browser compatibility.
    			script.onreadystatechange = cb;
    			script.onload = cb;
    
    			function cb() {
    				resolve();
    			}
    
    			// Fire the loading
    			head.appendChild( script );
    
    		} );
    		return promise;
    	}
    
    	// создаем ссылки на функции модуля в адресном пространстве модуля
    
    })(this.libs=this.libs||{});

    подключение модуля
    <!DOCTYPE html>
    <html>
    <head>
        <title>graph eginere</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script src="js/require.js" type="text/javascript" charset="utf-8"></script>
    </head>
    <body>
        ...
    </body>
    </html>

    как с помощью данного модуля загружать другие модули
    window.libs.require({
    		path: "js/",
    		modules: [
    			"polyfill.setimmediate.js",
    			"vector.js",
    			"events.js",
    		],
    		onready:()=>{
    			console.log("LOAD OK");
    		}
    	});

    пример модуля polyfill.setimmediate.js
    /**
     * Полифил для setImmediate 
     * (единственное что в неизмененном виде было взято гдето в Интернете)
     */
    if (!window.setImmediate) window.setImmediate = (function() {
    	var head = { }, tail = head; // очередь вызовов, 1-связный список
    
    	var ID = Math.random(); // уникальный идентификатор
    
    	function onmessage(e) {
    		if(e.data != ID) return; // не наше сообщение
    		head = head.next;
    		var func = head.func;
    		delete head.func;
    		func();
    	}
    
    	if(window.addEventListener) { // IE9+, другие браузеры
    		window.addEventListener('message', onmessage);
    	} else { // IE8
    		window.attachEvent( 'onmessage', onmessage );
    	}
    
    	return function(func) {
    		tail = tail.next = { func: func };
    		window.postMessage(ID, "*");
    	};
    }());

    пример модуля events.js
    (function(exports) {
    	console.log("Flow.Events");
    
    	"use strict";
    
    	/**
    	 * класс емиттера событий(почти eventemitter)
    	 * содержит функции on, once и emit
    	 */
    	exports.Events = Events;
    	function Events(){
    		// конструктор
    		//console.log("Events.constructor");
    		this.e = { };
    	};
    
    	/**
    	 * Установить слушатель для события @name
    	 * @param  {String}   name    стороковый идентификатор события
    	 * @param  {Function} cb      функция-слушатель. Вызывается при возникновении события @name
    	 * @param  {Number}   timeout функция-слушатель может быть вызвана 3-я разными способами 
    	 *                            1. незамедлительно при возникновении события (timeout не задан)
    	 *                            2. асинхронно, с незначительной отсрочкой (timeout равен 0)
    	 *                            3. асинхронно, через установленный интервал времени (timeout больше 0)
    	 * @param  {Boolean}  isOnce  если true, то слушатель будет вызван 1 раз, после чего будет удален
    	 * @return {Function}         функция, вызов которой удалит слушателя.
    	 */
    	Events.prototype.on = function(name, cb, timeout, isOnce) {
    		if (typeof cb !== 'function')
    			throw new Error('listener is not a function');
    		const e = this.e[name] = this.e[name]||[];
    		const d = this.mode(timeout);
    		if(isOnce) d.isOnce = true;
    		d.cb = cb;
    		e.push(d);
    		return function () {
    			const i = e.indexOf(d);
    			if(i!==-1) e.splice(i, 1);
    		}
    	};
    
    
    	/**
    	 * вычислить режим вызова обработчиков события
    	 * @param  {Number}   timeout функция-слушатель может быть вызвана 3-я разными способами 
    	 *                            1. незамедлительно при возникновении события (timeout не задан)
    	 *                            2. асинхронно, с незначительной отсрочкой (timeout равен 0)
    	 *                            3. асинхронно, через установленный интервал времени (timeout больше 0)
    	 * @return {Function}         Объект, может содержать поля поля timeout и isTimeout или isAsync или isSync
    	 */
    	Events.prototype.mode = function(timeout) {
    		const d = {};
    		if(typeof timeout === "number"){
    			if(timeout>0){
    				d.timeout = Math.ceil(timeout);	
    				d.isTimeout = true;
    			} 
    			else d.isAsync = true;
    		}
    		else d.isSync = true;
    		return d;
    	};
    
    	/**
    	 * установить глобальный режим вызова обработчиков события
    	 * @param  {Number}   timeout функция-слушатель может быть вызвана 3-я разными способами 
    	 *                            1. незамедлительно при возникновении события (timeout не задан)
    	 *                            2. асинхронно, с незначительной отсрочкой (timeout равен 0)
    	 *                            3. асинхронно, через установленный интервал времени (timeout больше 0)
    	 */
    	Events.prototype.setmode = function(timeout) {
    		 this.m = this.mode(timeout);
    	};
    
    	/**
    	 * отменить глобальный режим вызова обработчиков события
    	 */
    	Events.prototype.clearmode = function() {
    		 this.m = undefined;
    	};
    
    
    	/**
    	 * Установить одноразовый слушатель для события @name
    	 * @param  {String}   name    стороковый идентификатор события
    	 * @param  {Function} cb      функция-слушатель. Вызывается при возникновении события @name
    	 * @param  {Number}   timeout функция-слушатель может быть вызвана 3-я разными способами 
    	 *                            1. незамедлительно при возникновении события (timeout не задан)
    	 *                            2. асинхронно, с незначительной отсрочкой (timeout равен 0)
    	 *                            3. асинхронно, через установленный интервал времени (timeout больше 0)
    	 */
    	Events.prototype.once = function(name, cb, timeout) {
    		const off = this.on(name, function(){
    			off();
    			cb.apply(this,arguments);
    		}, timeout,true);
    	};
    
    	/**
    	 * Вызвать всех слушателей для события @name
    	 * @param  {String}   name    стороковый идентификатор события
    	 */
    	Events.prototype.emit = function(name) {
    		const e = this.e[name];
    		if(!e || !e.length) return;
    		const args = [].slice.call(arguments,1);
    		e.some( function(l) {
    			if(l.isEmitted) return;
    			if(l.isOnce) l.isEmitted = true;
    			const mode = this.m||l;
    			if(mode.isTimeout) {
    				setTimeout(function() { l.cb.apply(this, args); }, mode.timeout);
    			} else if(mode.isAsync) {
    				window.setImmediate(function() { l.cb.apply(this, args); });
    			} else {
    				l.cb.apply(this, args);
    			}
    			const event = args[0];
    			if(event.__stopImmediatePropagation) return true;
    			return false;
    		});
    	};
    })(this.libs=this.libs||{});

    Ответ написан
  • Как сделать из строки в строку, а затем массив?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Совершенно не понял суть этого вопроса:
    Надо сделать из final строку вида(1:17 где 1 цифра, а 17 сколько раз она повторилась),а потом массив;

    потому как final.innerHTML уже есть такая строка.

    Но взял на себя смелость слегка прилизать ваш "код"
    Ответ написан
  • Как сделать чтобы DOM элементы искало только по названию?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Вариант без регулярных выражений:

    Ответ написан
  • Как сделать точное вычисление физики гравитации на javascript в canvas методом Верле?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    elleremo, ускорение которое получают планеты пролетая вблизи других планет не является ошибкой!!!

    Этот эффект называется "гравитационный маневр для ускорения объекта" или же "гравитационная праща"

    Swingby_acc_anim.gifГравитационный манёвр для ускорения объекта (гравитационная праща)

    Не стал делать "точную имитацию" гравитации. Пошел по пути:
    1. каждый объект имеет массу равную объему объекта умноженному на плотность объекта
    2. каждый объект влияет на каждый динамический объект
    3. влияние пошагово рассчитывается по формуле (почти) :
    V = сумма(F); // суммарный вектор сил
    F = k*M/D; // сила влияния (расчитывается для каждого объекта оказывающего влияние на текущий)
    M - масса объекта
    D - квадрат расстояния между центрами масс объектов
    k - коэффициент для подгона скоростей (выполняет роль гравитационной постоянной)

    Алгоритм расчета (пошагово):
    1. Для каждого динамического объекта происходит расчет новых координат (сумма текущих координат и вектора скорости, рассчитанного на предыдущей итерации цикла симуляции)
    2. Каждый динамический объект сверяется с каждым объектом на предмет столкновения. Если расстояние между центрами 2х сравниваемых объектов меньше суммы их радиусов то происходит слияние. Если объединяются статичный и динамический объекты, то динамический удаляется а его масса добавляется к статическому с перерасчетом плотности, радиуса и объема. Если объединяются 2 динамических объекта то к первому добавляется масса второго с перерасчетом плотности, радиуса и объема, координаты и вектора скоростей пересчитываются как взвешеная сумма координат и векторов скоростей обоих объектов. После второй объект удаляется.
    3. Для каждого динамического объекта расчитывается сумма векторов силы влияния притяжения всех объектов. Затем данная сумма и вектор скорости текущего объекта суммируются
    4. Переход к новой итерации цикла симуляции.

    Вся реализация расчета тут (в конце скрипта). Все формулы вынесены в класс Calc.

    видеодемонстрация
    демонстрация (масштабируется колесиком мышки, перетаскивается с помощью ЛКМ)

    Добавил слияние планет при столкновении (массы суммируются, вектора скоростей суммируются, позиция переносится в центр масс)
    Добавил источники (автоматически генерируют планеты)
    Добавил отдельные кнопки для пуска и остановки источников

    5bbd21b57da99316097769.png
    Добавил настройки:
    • параметры отображения
      • отображать сетку - вкл/выкл отображение координатной сетки
      • отображать источники - вкл/выкл отображение объектов, генерирующих планеты
      • отображать шлейф - вкл/выкл отображение траектории планет

    • Настройки физических величин - позволяют задаь минимальные и максимальные значения для размеров и плотности статических и динамических объектов
    • Управление симуляцией
      • шаг симуляции - экспериментальная величина регулирующая точность расчетов
      • скорость источников - изменяет скорость, с которой источники генерируют планеты
      • включить источники - вкл/выкл генерацию планет источниками



    Доработал механизм расчета влияния гравитации, теперь у каждого объекта масса считается исходя из объема и плотности.
    Ввел изменение в процесс генерации новых планет, теперь они выставляются на лист с рассчитанной первой космической скоростью относительно центрального статичного объекта.
    Установил статичным объектам повышенную плотность, что существенно увеличило их массу (можно менять на панели настроек)
    Установил динамическим объектам пониженную плотность, что существенно уменьшило их массу и взаимовлияние (можно менять на панели настроек)

    5bbd22bc10be0483291405.png
    Ответ написан
    2 комментария
  • Как вывести рекурсивно?

    lastuniverse
    @lastuniverse
    Всегда вокруг да около IT тем
    Кристина, выкладываю на Ваш суд мою попытку объяснить суть рекурсии. Код имеет комментарии.
    сам код с пояснениями
    // итак, пусть будет задан некий абстрактный массив 
    // с произвольной глубиной вложенности
    // при этом элементами массива могут быть
    // строки и вложенные массивы
    const arr = [
      "string 1",
      "string 2",
      [
        "string 3.1",
        "string 3.2",
        [
          "string 3.3.1",
          [
            "string 3.3.2.1",
            "string 3.3.2.2"
          ],
          "string 3.3.3",
        ]
      ],
      "string 4",
      [
        "string 5.1",
        [
          "string 5.2.1",
          [
            "string 5.2.2.1",
            "string 5.2.2.2"
          ],
          "string 5.2.3"
        ]
      ]
    ];
    
    // так как глубина вложенности произвольная
    // для обхода всех элементов оптимальным
    // будет использовать рекурсивную функцию
    function parseArray(data) {
      let retstr = '';
      if(typeof data === "string"){
        // если строка, то выводим ее 
        // содержимое как элемент текущего списка
        retstr += '<li>'+data+'</li>';
      }else if(Array.isArray(data) ){
        // если массив, то создаем влеженный список
        retstr += '<ul>';
        // и каждый элемент массива отдаем на обработку
        // нашей функции, вызывая ее из нееже (это и есть рекурсия)
        // таким образом мы обеспечиваем обход
        // всех элементов нашей древовидной структуры
        // независимо от ее глубины вложенности и порядка
        // следования элементов
        data.forEach(value=>{
          retstr += parseArray(value);
        });
        // после прохода всех элементов внутри текущего
        // массива закрываем текущий список
        retstr += `</ul>`;
      }
      return retstr;
    }
    
    
    let wrap = document.querySelector('.wrap');
    wrap.innerHTML = parseArray(arr);

    Ответ написан
    2 комментария