• Одно ли и то же эти куски кода?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    1 - function expression
    Функция будет анонимная (без имени), что затруднит отладку, а так же не позволит делать рекурсивные вызовы.
    var всплывет наверх функции в которой была объявлена (оборачивающей), но до присваивания будет иметь значение undefined, вызов приведет к ошибке.
    Данный тип функций вообще не должен использоваться в нормальном коде.
    Функцию можно переопределить в последствии

    2 - named function expression
    Похоже на предыдущее, но имеет имя, что упрощает отладку и позволяет делать рекурсивные вызовы. В остальном все тоже самое.
    Вот так в переменную опять же присваивать не стоит, для дебага хватит стрелочной функции присвоенной в константу (в дебаггере примет имя константы). Но рационально использовать для колбэков, где нужна рекурсия или опять же для удобного дебага.

    3. function declaration
    Всегда должна иметь имя. Всплывает на верх (можно вызывать до объявления). Нельзя переопределить внутри той же функции (всегда будет вариант, тот что объявлен ниже).

    Добавлю еще 4 - arrow function expressionconst func = () => {};на сегодня лучше использовать его вместо function expression
    Ответ написан
    3 комментария
  • Как при рекурсивном переборе древовидных объектов вызывать fetch на каждый item и на выходе получать измененный массив?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    const addingOptions = arr => Promise.all(arr.map(
        item => Promise.all([
            fetchOptions(item.id),
            item.children.length ? addingOptions(item.children) : []
        ]).then(([options, children]) => ({
            ...item,
            options,
            children
        }))
    ));
    Ответ написан
    Комментировать
  • Как предлагать пользователям рандомный вопрос?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Комментировать
  • Аналог electron только на GO?

    bingo347
    @bingo347
    Crazy on performance...
    Electron построен поверх CEF внедренного в ноду как нативный аддон.
    В рендер процессе нода подключается через libnode
    Все это вполне общается через сишный abi с которым умеет работать cgo.
    Ответ написан
    Комментировать
  • Как реализовать такое?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Для начала наш бэк должен уметь отвечать на запрос вида "дай мне N товаров после товара X", иначе такая кнопка в принципе не имеет смысл.
    Так вот, при нажатии на кнопку "Показать больше" мы первым делом должны ее заблокировать (чтоб пользователь не на тыкал лишнего) и показать лоадер (вдруг инет пользователя медленный), а затем отправить наш запрос к бэку, чтоб он дал нам данные о дополнительных товарах.
    Когда данные загрузились, отрисовываем их в конец и в зависимости от того, есть ли у бэка еще товары (это он тоже должен нам сказать) мы или разблокируем или прячем кнопку "Показать больше".
    Все.
    Ответ написан
    Комментировать
  • Какой язык поможет научиться грамотно подходить разработке на БЭ?

    bingo347
    @bingo347
    Crazy on performance...
    Хотите, чтоб компилятор бил по рукам за почти любые грехи - попробуйте Rust, хорошие практики он Вам точно привьет, а там глядишь, пока изучаете эти самые практики, и вакансий на нем больше будет.
    Но в любом случае, после Rust и на TS начинаешь писать иначе, лучше.
    Ответ написан
    Комментировать
  • Как найти и заменить значение вложенного объекта?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    function cloneWithReplace(
        // клонируемый объект
        obj,
        // объект с функциями вида value => newValue, в соответствующих ключах для замены
        // нужен не всегда, поэтому по умолчанию сделаем пустой объект
        replacers = {},
        // Map с значениями, которые уже склонировали, дабы не попасть в рекурсию
        // так как внешний код обычно его не будет передавать, зададим значение по умолчанию
        storeMap = new Map()
    ) {
        // для начала чекнем, что объект уже клонировали:
        if(storeMap.has(obj)) {
            return storeMap.get(obj);
        }
    
        // получим тип объекта, он нам пригодится пару раз, дабы отличать функции
        const type = typeof obj;
    
        // если obj примитив, то его можно просто вернуть
        if(obj === null || (type !== 'object' && type !== 'function')) {
            return obj;
        }
    
        // создадим переменную с результатом и инициируем ее в зависимости от типа оригинала
        let result;
        if(type === 'function') {
            // функцию можно "склонировать" лишь обернув
            result = function() {
                return obj.apply(this, arguments);
            };
            // неплохо бы, чтоб клон правильно сообщал имя функции и количество аргументов
            // но так как IE не ест такую магию, обернем в try-catch
            try {
                Object.defineProperties(result, {
                    name: Object.getOwnPropertyDescriptor(obj, 'name'),
                    length: Object.getOwnPropertyDescriptor(obj, 'length')
                });
            } catch {}
        } else if(Array.isArray(obj)) {
            // массивы клонируем рекурсивно, при помощи map
            result = obj.map(value => cloneWithReplace(value, replacers, storeMap));
            // так как нормальные массивы не содержат других полей, кроме числовых
            // можно сохранить клон в защиту от рекурсии и вернуть результат
            storeMap.set(obj, result);
            return result;
        } else {
            // для всех других объектов просто создадим новый объект и скопируем ему ссылку на прототип
            result = Object.setPrototypeOf({}, Object.getPrototypeOf(obj));
        }
    
        // сохраним клон в защиту от рекурсии
        storeMap.set(obj, result);
    
        // осталось склонировать поля с заменой тех случаев, где у нас есть replacer
        for(const key of Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))) {
            if(typeof replacers[key] === 'function') {
                // если есть replacer используем его
                result[key] = replacers[key](obj[key]);
            } else {
                // иначе клонируем поле рекурсивно
                result[key] = cloneWithReplace(obj[key], replacers, storeMap);
            }
        }
    
        return result;
    }
    
    // используем так:
    const newData = cloneWithReplace(data, {
        value: () => 'new value'
    });
    Ответ написан
    1 комментарий
  • Github: Один локальный репозиторий на два удаленных?

    bingo347
    @bingo347
    Crazy on performance...
    https://git-scm.com/book/ru/v2/Инструменты-Git-Под...
    сделать папку build подмодулем, у которого remote будет публичный репо
    Ответ написан
    Комментировать
  • Как изменить текст в буфере перед вставкой?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    document.addEventListener('paste', pasteText);
    function pasteText(e) {
      e.preventDefault();
      var txt = (e.originalEvent || e).clipboardData.getData('text/plain');
      e.target.value = txt;
    };
    Ответ написан
    1 комментарий
  • Есть программа для создания таблиц с программным кодом?

    bingo347
    @bingo347
    Crazy on performance...
    В экселе в ячейку можно вставить функции, в том числе написанные собственноручно на VBA
    В OpenOffice/LibreOffice Calc помимо VBA так же доступны Lua и JS
    В Google Sheets то же самое можно сделать на JS
    Ответ написан
  • Как работает get и set в computed?

    bingo347
    @bingo347
    Crazy on performance...
    Это не геттер и сеттер без имени, это методы с именами get и set.
    Ответ написан
    Комментировать
  • Выполнить функцию когда скролл на нужной позиции?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Комментировать
  • Как сравнить дату с датой из объекта?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Дату в объекте нужно распарсить в объект Date
    Сами даты приводятся операторами сравнения к числу (unix timestamp в милисекундах) и вполне себе сравниваются:
    const date = new Date('02-10-2005'); // это лучше вынести за цикл, что бы не делать много раз одно и то же
    for (card of json.CardInfo) {
       if(new Date(card.Date) < date) {
        console.log('true');
      } else{
        console.log('false');
      }
    }

    P.S. вообще конструкций вида if(...) { true } else { false } лучше избегать
    for (card of json.CardInfo) {
        console.log(String(new Date(card.Date) < date));
    }
    этот пример отработает абсолютно аналогично предыдущему, но читать кода тут меньше
    Ответ написан
    7 комментариев
  • Стоит ли учить С/С++ если не планируешь писать на нём?

    bingo347
    @bingo347
    Crazy on performance...
    Языки не нужно учить. Это крайне вредно. Ну заучите Вы синтаксис и базовые принципы, а что дальше? Программировать с этим Вы не сможете. Подход выучить ЯП Х не работает, как и не работает подход выучить естественный. Просто подумайте, кто быстрее заговорит на английском - тот кто выучит много слов и правил или тот кто поедет в США и будет вынужден там общаться? С языками программирования все то же самое.

    Теперь о C и C++
    C наверно самый простой ЯП, проще только ассемблер. Из высокоуровневых абстракций в нем только типы данных да структурное программирование (if, for, while, ...). Вы скорее всего уже с этим всем знакомы. Из нового разве что будет работа с указателями, опять же максимально простым способом - в лоб.
    C++ - обвешали простой C максимальным количеством высокоуровневых абстракций (все виды полиморфизма, ООП, замыкания, динамическая диспетчеризация и т.д.), что сделало его очень сложным. Вам понадобятся годы практики (практики, а не зубрежки!), чтобы просто понять, что здесь происходит. А скорее всего Вы просто бросите это дело, породив пару десятков UB в простейшей программе и на ровном месте.
    Ответ написан
    Комментировать
  • Какой самый низкоуровневый язык програмирования?

    bingo347
    @bingo347
    Crazy on performance...
    Ассемблеры разные бывают, по сути для каждой архитектуры существует свой ассемблер. А еще для разных ОС могут быть диалекты. Ассемблер - это прямое соотношение машинных команд с более человекопонятным ассемблерными, нумерации регистров с их именами и т.д. Так что что-то посередине воткнуть не получится.

    P.S. когда уже русский язык станет самым популярным? Как Вы собираетесь с формальными языками разбираться, если не можете освоить естественный?
    Ответ написан
    1 комментарий
  • Как работает сборщик мусор с колбеками Promise?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Сборщики мусора (далее GC) бывают разные, в том же v8 используется сразу 3 типа GC в зависимости от поколения объектов (упрощенно молодое, старое и сложные случаи), но в большинстве своем принцип работы сводится к просчету достижимости из некоторого корня в дереве объектов (например глобального объекта, но не только его). v8 не является исключением, и его GC содержит C++ api для создания таких корней. Из JS мы данным api можем воспользоваться лишь косвенно, через сущности языка предоставляемые либо самим v8 либо платформой (браузером, node.js, deno и т.д.)
    Чтоб было понятно давайте рассмотрим простой пример:
    const h = 'Hello world!';
    const n = 'nothing';
    setTimeout(() => {
      console.log(h);
    }, 1000);
    У нас есть строковые переменные h и n. Переменная n нигде больше не используется и ее память очистится при ближайшей работе GC. А вот переменная h оказалась в замыкании созданном стрелочной функцией. И хотя в JS мы не можем достучаться до h имея ссылку на эту функцию, сама функция все таки имеет ссылку на h, а значит h не может быть уничтожена пока не будет уничтожена сама функция. В терминах GC ссылка на h будет серой, то есть сама ссылка на h недоступна из корня напрямую, но сейчас мы проверяем объекты, которые на нее ссылаются и истина будет зависеть от них (подробнее можете погуглить "mark black white and gray memory in gc").
    Давайте посмотрим на саму стрелочную функцию, которая держит h в замыкании. Из кода видно, что мы ее передаем в функцию setTimeout, о которой известно, что это api предоставленное платформой (а значит вероятно какая-то часть написана на C++), а так же, что она асинхронная. Платформе реализующей setTimeout наша функция понадобится после асинхронного ожидания и никто платформе не сможет гарантировать, что во время этого ожидания не будет работы GC, поэтому ей ничего не остается, кроме как запросить у v8 создание нового корневого дерева объектов, в которое и будет положена ссылка на данную функцию.
    После же выполнения таймаута платформе больше не нужна наша функция, поэтому ссылка на нее будет удалена из дерева объектов. А так как других ссылок на функцию нет, и она больше не доступна ни из одного корня - GC удалит из памяти и функцию и строку связанную h, которая так же стала недоступна из корня.

    Посмотрим на пример из вопроса. У нас есть стрелочная функция, которая удерживает на себе инстанс компонента через this ссылку (так как стрелочные функции замыкают this). Саму функцию в памяти удерживает промис порожденный вызовом loader('url'), так как мы отдали её в метод then. Других ссылок на данную функцию нет, а значит и сама функция и ее замыкание (инстанс компонента) будут "жить" не менее "жизни" промиса.
    Скажем был отправлен запрос на сервер, но потом компонент в котором был объявлен промис и колбек был удален.
    И после удаления приходит ответ от сервера, и он выполнит колбек. Это значит что колбек остался в памяти со всеми переменными контекста
    Если других ссылок не осталось, то инстанс компонента будет удерживаться от очистки через промис.

    Теперь стоит разобраться с самим промисом. У него может быть 3 состояния - pending, resolved или rejected. После перехода в состояния resolved или rejected промис может выполнить сохраненные колбэки в ближайшем микротаске, а после он удалит на них ссылки из себя, в следствии чего, память удерживаемая замыканием колбэка может быть очищена (при отсутствии на нее других ссылок, достижимых из какого-либо корня).
    В состоянии pending промис может потенциально находится бесконечно долго, при этом ссылаясь на все колбэки переданные ему в методы then, catch или finally, а значит так же косвенно ссылаясь на их замыкания. И тут все зависит от того, кто ссылается на данный промис, и достижим ли он из корня. И да, промис вполне может быть удален из памяти так и не дождавшись своего завершения.
    интересное умозаключение
    Если Promise - это обещание, то в данном случае оно будет нарушено?


    В комментах к вопросу есть еще один интересный пример:
    function getSomething(){
      return new Promise((resolve, reject)=>{
        if(sys_condition){
           resolve();
        } 
      })
    }
    
    function testPromise(){
      let config = {....}
      getSomething().then(()=>{
         #use config
         goOn(...config)
      })
    }
    
    testPromise();
    У нас есть вызванная 1 раз функция testPromise, которая получает из функции getSomething промис, в который с помощью метода then сохраняет колбэк, удерживающий в замыкании переменную config. Сам промис она нигде не сохраняет, что здесь очень важно.
    В функции getSomething мы просто возвращаем промис созданный через его конструктор, который как мы уже знаем нигде больше не сохраняется. И на этом могло бы все и закончится, без вызова колбэка независимо ни от чего. Но конструктор промиса выполняет свой колбэк синхронно, а кроме того он передает в него 2 функции - resolve и reject, которые в своем замыкании ссылаются на только что созданный промис (а это уже 2 ссылки на него, хотя мы то его никуда не сохраняли). Переменная reject никак не используется, а значит спокойно может быть удалена после завершения колбэка. Переменная resolve просто вызывается как функция внутри условия, но более тоже никак не используется и никуда не сохраняется, а значит так же может быть удалена.
    В этом примере. если sys_condition = false и resolve не вызовется, это значит что создается утечка памяти
    Нет, утечки памяти не будет. Колбэк созданный в testPromise будет удален вместе с замыканием, так и не вызвавшись ни разу.
    Ответ написан
    3 комментария
  • Как отсортировать объект по вложенному массиву?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    const newArray = arr.slice(); // так как sort мутирует массив, а нужен новый
    const isAnnaSkill = skill => skill.name === 'Anna';
    const getAnnaLevel = item => item.skills.find(isAnnaSkill)?.level;
    newArray.sort((a, b) => getAnnaLevel(b) - getAnnaLevel(a));
    Ответ написан
    2 комментария
  • Как обработать 2 запроса одновременно в node.js?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    Комментировать