Страницы

Поиск по вопросам

четверг, 4 октября 2018 г.

Подскажите модульную систему js

Начал программировать на js, но опыта мало. Хотелось бы как на php иметь аналогию с классами. Чтобы писал в один файл модуль и потом его при необходимости подключал в файле. + Было бы преимуществом чтобы это потом можно было в 1 js файл компилировать. Подскажите пожалуйста какой фреймворк или библиотеку использовать под эти нужды? Или возможно какая то статья затрагивающая эту тему будет не лишней. Спасибо


Ответ

В современной экосистеме JavaScript можно выделить несколько подходов к разбиению кода на модули:
AMD - формат описания модулей, используемый в Require.js. На мой ( очень субъективный) взгляд описание модулей несколько избыточно. Одна из основных "фишек" - асинхронная динамическая загрузка модулей по требованию. Хотя, если не изменяет память, есть и возможность собрать весь код в один пакет. Пример описания AMD модуля:
// Описание зависимостей define(['jquery', 'foo', 'bar'], function (jquery, foo, bar) { // Определение самого модуля return function () {}; }); Common.js - подход, используемый, например, в Node.js экосистеме. Типичный модуль имеет вид:
// Импортируем зависимости var jquery = require('jquery'), foo = require('foo'), bar = require('bar');
// Экспортируем тело модуля module.exports = function() {}; UMD - комбинированный подход, позволяющий описывать модули, работающие как в AMD инфраструктуре, так и в Common.js. Является ничем иным, как средством совместимости. Модули ES2015 - специальный синтаксис, введенный в стандарт ES2015 позволяющий разбивать код на модули. Пример модуля:
// Импортируем зависимости import 'jquery' as $; import foo from 'foo'; import bar from 'bar';
// Экспортируем тело модуля export default function() {};
Плохая новость заключается в том, что ни один из подходов к описанию модулей не может работать в браузере напрямую. Вам в любом случае придется подключать некую стороннюю библиотеку для управления модулями. Для AMD - это Require.js; для Common.js - Browserify, Webpack и другие; для ES2015 - это может быть связка Browserify + Babel или что-то еще.
Для новых проектов я бы порекомендовал вам обратить внимание на ES2015 модули и на Common.js модули. Тому есть несколько причин:
Экосистема Node.js использует Common.js модули. Используя систему сборки вроде Browserify вы можете использовать npm модули. Это позволит вам писать код, который будет выполняться как на сервере, так и на клиенте. При использовании современных систем сборки вы сможете практически без проблем комбинировать модули ES2015 и Common.js Хотя сегодня в браузерах нет встроенных средств загрузки модулей ES2015, все идет к тому, что рано или поздно они появятся.
Что почитать:
https://addyosmani.com/writing-modular-js/ https://learn.javascript.ru/modules http://frontender.info/es6-modules/ https://habrahabr.ru/post/181536/ Очевидно, есть и другие статьи по теме. Google расскажет вам о них лучше меня. =)

Подскажите модульную систему js

Начал программировать на js, но опыта мало. Хотелось бы как на php иметь аналогию с классами. Чтобы писал в один файл модуль и потом его при необходимости подключал в файле. + Было бы преимуществом чтобы это потом можно было в 1 js файл компилировать. Подскажите пожалуйста какой фреймворк или библиотеку использовать под эти нужды? Или возможно какая то статья затрагивающая эту тему будет не лишней. Спасибо


Ответ

В современной экосистеме JavaScript можно выделить несколько подходов к разбиению кода на модули:
AMD - формат описания модулей, используемый в Require.js. На мой ( очень субъективный) взгляд описание модулей несколько избыточно. Одна из основных "фишек" - асинхронная динамическая загрузка модулей по требованию. Хотя, если не изменяет память, есть и возможность собрать весь код в один пакет. Пример описания AMD модуля:
// Описание зависимостей define(['jquery', 'foo', 'bar'], function (jquery, foo, bar) { // Определение самого модуля return function () {}; }); Common.js - подход, используемый, например, в Node.js экосистеме. Типичный модуль имеет вид:
// Импортируем зависимости var jquery = require('jquery'), foo = require('foo'), bar = require('bar');
// Экспортируем тело модуля module.exports = function() {}; UMD - комбинированный подход, позволяющий описывать модули, работающие как в AMD инфраструктуре, так и в Common.js. Является ничем иным, как средством совместимости. Модули ES2015 - специальный синтаксис, введенный в стандарт ES2015 позволяющий разбивать код на модули. Пример модуля:
// Импортируем зависимости import 'jquery' as $; import foo from 'foo'; import bar from 'bar';
// Экспортируем тело модуля export default function() {};
Плохая новость заключается в том, что ни один из подходов к описанию модулей не может работать в браузере напрямую. Вам в любом случае придется подключать некую стороннюю библиотеку для управления модулями. Для AMD - это Require.js; для Common.js - Browserify, Webpack и другие; для ES2015 - это может быть связка Browserify + Babel или что-то еще.
Для новых проектов я бы порекомендовал вам обратить внимание на ES2015 модули и на Common.js модули. Тому есть несколько причин:
Экосистема Node.js использует Common.js модули. Используя систему сборки вроде Browserify вы можете использовать npm модули. Это позволит вам писать код, который будет выполняться как на сервере, так и на клиенте. При использовании современных систем сборки вы сможете практически без проблем комбинировать модули ES2015 и Common.js Хотя сегодня в браузерах нет встроенных средств загрузки модулей ES2015, все идет к тому, что рано или поздно они появятся.
Что почитать:
https://addyosmani.com/writing-modular-js/ https://learn.javascript.ru/modules http://frontender.info/es6-modules/ https://habrahabr.ru/post/181536/ Очевидно, есть и другие статьи по теме. Google расскажет вам о них лучше меня. =)

Чем отличаются потоки от нитей?

Вроде как должно быть одно и тоже, так как thread переводят и как "поток", и как "нить". Вроде как, при создании потока (нити) и в послед запуске он может разбиваться на нити?
Это поток порождает себе подобных (потоки такие же как и он) или же он порождает нити (которые видимо являются неполноценными потоками)?
А еще, являются ли потоки чтения (с консоли, файла) и вывода (в файл) такими же потоками?
Почему тогда мы не вызываем у них методы start и пр., а только close?
Или же можно запустить нить создав лишь объект их типа?
Неужели это все одни и те же потоки? И еще, наличие 2-х нитей c thread и с runnable обусловлено тем, что с 1-ым нельзя наследоваться, но легче запускать, а со 2м можно наследоваться, но сложнее запускать?


Ответ

Вроде как должно быть одно и тоже , тк thread переводят и так , и так.
Одно и то же. Вот если встретите термин Fiber - там все немного интересней, взаимодействие с ним происходит как с потоком, но классическим ОС-потоком он не является.
Вроде как , при создании потока(нити) и в послед запуске он может разбиваться на нити?
Разбиваться не может, порождать - может. Порожденные потоки имеют ровно те же возможности.
А еще , являются ли потоки чтения(с консоли,файла) и вывода(в файл) такими же потоками?
Нет, мы говорим про потоки выполнения, а это - потоки данных, т.е. просто последовательная перекачка байтов из одного места в другое.
И еще , наличие 2х нитей c thread и с runnable обусловлено тем , что с 1ым нельзя наследоваться , но легче запускать ,а со 2м можно наследоваться , но сложнее запускать?
не берусь судить за архитекторов API, но наследоваться от класса потока вам не стоит вообще никогда. В большинстве случаев вам так вообще потребуется ExecutorService, который возьмет на себя управление потоками, а вы будете просто отдавать ему задачи на выполнение в виде Runnable или аналога.

Чем отличаются потоки от нитей?

Вроде как должно быть одно и тоже, так как thread переводят и как "поток", и как "нить". Вроде как, при создании потока (нити) и в послед запуске он может разбиваться на нити?
Это поток порождает себе подобных (потоки такие же как и он) или же он порождает нити (которые видимо являются неполноценными потоками)?
А еще, являются ли потоки чтения (с консоли, файла) и вывода (в файл) такими же потоками?
Почему тогда мы не вызываем у них методы start и пр., а только close?
Или же можно запустить нить создав лишь объект их типа?
Неужели это все одни и те же потоки? И еще, наличие 2-х нитей c thread и с runnable обусловлено тем, что с 1-ым нельзя наследоваться, но легче запускать, а со 2м можно наследоваться, но сложнее запускать?


Ответ

Вроде как должно быть одно и тоже , тк thread переводят и так , и так.
Одно и то же. Вот если встретите термин Fiber - там все немного интересней, взаимодействие с ним происходит как с потоком, но классическим ОС-потоком он не является.
Вроде как , при создании потока(нити) и в послед запуске он может разбиваться на нити?
Разбиваться не может, порождать - может. Порожденные потоки имеют ровно те же возможности.
А еще , являются ли потоки чтения(с консоли,файла) и вывода(в файл) такими же потоками?
Нет, мы говорим про потоки выполнения, а это - потоки данных, т.е. просто последовательная перекачка байтов из одного места в другое.
И еще , наличие 2х нитей c thread и с runnable обусловлено тем , что с 1ым нельзя наследоваться , но легче запускать ,а со 2м можно наследоваться , но сложнее запускать?
не берусь судить за архитекторов API, но наследоваться от класса потока вам не стоит вообще никогда. В большинстве случаев вам так вообще потребуется ExecutorService, который возьмет на себя управление потоками, а вы будете просто отдавать ему задачи на выполнение в виде Runnable или аналога.

Симметрическая разность

Симметрическая разность wiki Нужно найти симметрическую разность массивов. Написал функцию сравнения двух массивов, в которой объединяю массивы в один и в цикле ищу повторяющиеся значения. При нахождении удаляю.
function sym() { var args = Array.prototype.slice.call(arguments); var result = compareTwoArray(arguments[0], arguments[1]); if (arguments.length > 2) { for (var i = 2; i < arguments.length; i++) { // console.log('result = ' + result); result = compareTwoArray(result, arguments[i]); } } return result; } function compareTwoArray() { var args = Array.prototype.slice.call(arguments); var result = []; var newArr = args.reduce(function(prev, curr) { return prev.concat(curr); }) for (var i = 0; i < newArr.length; i++) { var count = 0; for (var j = i+1; j < newArr.length; j++) { if (newArr[i] === newArr[j]) { count += 1; newArr.splice(j, 1); j -= 1; } } if (count === 0) { result.push(newArr[i]); } } return result; } console.log(sym([1, 2, 3], [3, 1, 5])); // [2, 5] console.log(sym([1, 1, 3], [4, 6])); // [1, 3, 4, 6] console.log(sym([1, 1, 2, 5], [2, 2, 3, 5])); // [1, 3] console.log(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])); // [1, 4, 5] console.log(sym([1, 2, 5], [2, 3, 5], [3, 4, 5])); // [1, 4, 5]
Не знаю, как обрабатывать повторяющиеся значения. В одном случае его нужно удалить.
[1, 2, 3] [3, 1, 5] [2, 5] - должен получиться [2, 5] - получается с моим кодом
В другом оставить.
[1, 1, 3] [4, 6] [1, 3, 4, 6] - должен получиться [3, 4, 6] - получается с моим кодом
В другом и оставить(1) и удалить(2).
[1, 1, 2, 5] [2, 2, 3, 5] [1, 3] - должен получиться [3] - получается с моим кодом


Ответ

Решение для двух массивов. Хотя 3 и больше массивов можно обрабатывать ступенчато: сначала два первых, потом результат первой обработки и 3 массив и так далее.
function sum(arr1, arr2) { var tmp = arr1.concat(arr2), result = [], value, sum; for (var i = 0; i < tmp.length; i++) { var value = tmp[i]; if (result.indexOf(value) == -1) { sum = 0; if (arr1.indexOf(value) != -1) { sum++; } if (arr2.indexOf(value) != -1) { sum++; } if (sum == 1) { result.push(value); } } } return result; } console.log(sum([1, 2, 3], [3, 1, 5])); // [2, 5] console.log(sum([1, 1, 3], [4, 6])); // [1, 3, 4, 6] console.log(sum([1, 1, 2, 5], [2, 2, 3, 5])); // [1, 3]

Симметрическая разность

Симметрическая разность wiki Нужно найти симметрическую разность массивов. Написал функцию сравнения двух массивов, в которой объединяю массивы в один и в цикле ищу повторяющиеся значения. При нахождении удаляю.
function sym() { var args = Array.prototype.slice.call(arguments); var result = compareTwoArray(arguments[0], arguments[1]); if (arguments.length > 2) { for (var i = 2; i < arguments.length; i++) { // console.log('result = ' + result); result = compareTwoArray(result, arguments[i]); } } return result; } function compareTwoArray() { var args = Array.prototype.slice.call(arguments); var result = []; var newArr = args.reduce(function(prev, curr) { return prev.concat(curr); }) for (var i = 0; i < newArr.length; i++) { var count = 0; for (var j = i+1; j < newArr.length; j++) { if (newArr[i] === newArr[j]) { count += 1; newArr.splice(j, 1); j -= 1; } } if (count === 0) { result.push(newArr[i]); } } return result; } console.log(sym([1, 2, 3], [3, 1, 5])); // [2, 5] console.log(sym([1, 1, 3], [4, 6])); // [1, 3, 4, 6] console.log(sym([1, 1, 2, 5], [2, 2, 3, 5])); // [1, 3] console.log(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])); // [1, 4, 5] console.log(sym([1, 2, 5], [2, 3, 5], [3, 4, 5])); // [1, 4, 5]
Не знаю, как обрабатывать повторяющиеся значения. В одном случае его нужно удалить.
[1, 2, 3] [3, 1, 5] [2, 5] - должен получиться [2, 5] - получается с моим кодом
В другом оставить.
[1, 1, 3] [4, 6] [1, 3, 4, 6] - должен получиться [3, 4, 6] - получается с моим кодом
В другом и оставить(1) и удалить(2).
[1, 1, 2, 5] [2, 2, 3, 5] [1, 3] - должен получиться [3] - получается с моим кодом


Ответ

Решение для двух массивов. Хотя 3 и больше массивов можно обрабатывать ступенчато: сначала два первых, потом результат первой обработки и 3 массив и так далее.
function sum(arr1, arr2) { var tmp = arr1.concat(arr2), result = [], value, sum; for (var i = 0; i < tmp.length; i++) { var value = tmp[i]; if (result.indexOf(value) == -1) { sum = 0; if (arr1.indexOf(value) != -1) { sum++; } if (arr2.indexOf(value) != -1) { sum++; } if (sum == 1) { result.push(value); } } } return result; } console.log(sum([1, 2, 3], [3, 1, 5])); // [2, 5] console.log(sum([1, 1, 3], [4, 6])); // [1, 3, 4, 6] console.log(sum([1, 1, 2, 5], [2, 2, 3, 5])); // [1, 3]

Какое может быть практическое обоснование такой комбинации switch и while?

На просторах сети нашел несколько "странное" применение конструкций языка. Вот небольшой пример, который я набросал сам, просто по "шаблону":
#include using namespace std;
void foo(const int i) { cout << "foo(" << i <<")" << endl; }
int main() { int c = 10; switch(c&3) while((c-=4)>=0) { foo(c); case 3: foo(c); case 2: foo(c); case 1: foo(c); case 0:; } return 0; }
Специально для незнающих не раскрываю "мелочи", пусть будет интригой) От "знающих" прошу чисто практический пример - и с объяснениями мелочей. Почему сия конструкция иногда (или часто?) дает профит.


Ответ

Это по сути ручная размотка цикла, известная как Duff's device. Сейчас она практически не нужна, так как современные компиляторы делают это сами, если считают нужным. (А «считать нужным» они умеют намного лучше нас.)
Для старых компиляторов имело смысл, т. к. позволяло сэкономить на управлении циклом, выполняя по нескольку итераций (в вашем случае — 4) за раз. Странный код с switch нужен, понятно, для того, чтобы правильно работал случай, когда длина цикла не кратна размеру размотки.