Looks like no one added any tags here yet for you.
Сколько способ есть создать объект без прототипа?
1. Использование Object.create(null)
Самый распространённый способ — использовать метод Object.create()
с аргументом null
:
Пояснение:
Object.create(null)
создаёт новый объект, у которого нет прототипа.
Такой объект не наследует от Object.prototype
и, следовательно, не имеет никаких встроенных методов или свойств, таких как toString
, hasOwnProperty
и т.д.
2. Использование Object.setPrototypeOf()
Начиная с ECMAScript 2015 (ES6), вы можете использовать метод Object.setPrototypeOf()
или свойство __proto__
(не рекомендуется из-за устаревания):
Пояснение:
Создаём обычный объект с помощью {}
.
Затем устанавливаем его прототип равным null
с помощью Object.setPrototypeOf(obj, null)
.
Практическое применение
Пример использования объекта без прототипа в качестве словаря:
const dictionary = Object.create(null);
dictionary['apple'] = 'A fruit';
dictionary['car'] = 'A vehicle';
console.log(dictionary['apple']); // 'A fruit'
console.log(dictionary.hasOwnProperty); // undefined
Если у объекта нет прототипа чем это хорошо?
Преимущества объектов без прототипа
Чистый словарь (хеш-таблица):
Отсутствие конфликтов с предопределёнными свойствами: Объект без прототипа не содержит наследуемых свойств, таких как toString
, hasOwnProperty
и т.д. Это предотвращает случайные конфликты при использовании пользовательских ключей, которые могут совпадать с именами этих свойств.
Безопасность: При работе с данными от пользователя исключается риск использования или переопределения наследуемых методов, что может предотвратить потенциальные уязвимости.
Улучшенная производительность при определённых условиях:
Быстрый доступ к свойствам: Отсутствие цепочки прототипов может немного ускорить поиск свойств, так как движку не нужно проходить по прототипам при поиске.
Экономия памяти: Поскольку объект не содержит лишних свойств и методов, это может немного снизить потребление памяти, особенно при создании большого количества таких объектов.
Если у объекта нет прототипа чем это плохо?
Недостатки объектов без прототипа
Отсутствие встроенных методов:
Нет доступа к методам Object.prototype
: Объект не имеет методов, таких как toString()
, valueOf()
, hasOwnProperty()
, isPrototypeOf()
и т.д.
Дополнительные сложности при разработке: Необходимо быть осторожным при проверке свойств и использовать альтернативные методы.
Совместимость с кодом и библиотеками:
Проблемы с некоторыми функциями и библиотеками: Некоторые функции или библиотеки могут предполагать, что объект имеет прототип, и могут работать некорректно или вызвать ошибки.
Отсутствие поддержки некоторых операций: Методы, полагающиеся на наличие прототипа, не будут работать с такими объектами.
Неожиданное поведение:
Ошибки при вызове несуществующих методов: Попытка вызвать метод, отсутствующий в объекте, приведёт к ошибке, что может быть неожиданно для разработчика.
Сложности с отладкой: Отсутствие методов может усложнить процесс отладки и логирования.
Когда нужно делать объект без прототипа?
Когда использовать объекты без прототипа
Создание словарей или хеш-таблиц:
Когда необходимо хранить данные в формате ключ-значение без риска конфликтов с наследуемыми свойствами.
Обработка данных от пользователя:
При необходимости гарантировать, что пользовательские данные не переопределят важные методы или свойства.
Безопасное хранение конфигураций или настроек:
Для предотвращения непреднамеренного доступа или изменения встроенных свойств.
Как работает instanceof
под капотом?
Оператор instanceof
в JavaScript используется для проверки, является ли объект экземпляром определённого класса (функции-конструктора) или наследуется ли он от него по цепочке прототипов. Он возвращает логическое значение true
или false
.
obj instanceof Animal;
Проверка типа правого операнда:
Если Animal не является функцией с доступным свойством prototype
, возникает ошибка TypeError
.
Получение свойства prototype
конструктора:
JavaScript извлекает prototype
из Animal, то есть Animal.prototype
.
Получение внутреннего свойства [[Prototype]]
объекта obj
:
Это внутреннее свойство, которое указывает на прототип объекта (можно получить через Object.getPrototypeOf(obj)
).
Циклическая проверка цепочки прототипов:
JavaScript повторяет следующие шаги:
Сравнивает текущий прототип с Constructor.prototype
.
Если они совпадают, возвращает true
.
Если прототип равен null
, возвращает false
.
Если нет, переходит к прототипу прототипа и повторяет цикл.
Может ли оператор instanceof
проверить класс на наличие всех полей?
Нет, оператор instanceof
не проверяет наличие всех полей (свойств) объекта. Он только определяет, является ли объект экземпляром определённого класса или наследуется ли он от него по цепочке прототипов.
Почему instanceof
не подходит для проверки полей?
Ограниченность функционала:
Оператор instanceof
не предназначен для проверки содержимого объектов.
Его задача — определить наследование по цепочке прототипов.
Динамическое добавление полей:
В JavaScript нет строгой структуры объектов.
Объекты могут иметь разные наборы свойств, даже если они созданы одним и тем же конструктором.
Что такое тип Object
и какова его цель в JavaScript?
В JavaScript, Object
является фундаментальным встроенным типом и функцией-конструктором, который служит основой для всех других объектов. Он представляет собой наиболее общее понятие объекта и предоставляет базовые функциональные возможности для работы с объектами.
Область видимости в JavaScript
Глобальная область видимости
Функциональная (локальная) область видимости
Блочная область видимости
Лексическая область видимости
Особенности
Переменные, объявленные с помощью var
, имеют функциональную область видимости.
Локальные переменные не влияют на переменные с тем же именем в глобальной области или в других функциях.
Переменные, объявленные с помощью let
или const
, имеют блочную область видимости.
Что такое лексическая область видимости?
Лексическая область видимости this
В JavaScript значение this
определяется тем, как функция вызывается, а не тем, где она объявлена. Однако стрелочные функции (ES6) имеют лексическое значение this
, которое определяется местом их объявления.
Что такое IIFE?
IIFE (Immediately Invoked Function Expression) — это функция в JavaScript, которая объявляется и немедленно вызывается сразу же после своего создания. Такой подход позволяет создавать изолированные области видимости, предотвращая загрязнение глобального пространства имен и обеспечивая приватность данных.
2 Варианта
Обычная функция
Стрелочная
(function () {
// Код функции
})();
(() => {
// Код функции
})();
Где можно использовать замыкания кроме функций?
Классы и Методы Классов
Обработчики Событий
Генераторы и Асинхронные Генераторы
Контекстные Менеджеры и Реактивное Программирование
Пример
class Counter {
constructor() {
let count = 0; // Приватная переменная через замыкание
this.increment = function () {
count++;
console.log(count);
};
this.getCount = function () {
return count;
};
}
}
const counter = new Counter();
counter.increment(); // Вывод: 1
counter.increment(); // Вывод: 2
console.log(counter.getCount()); // Вывод: 2
Пример
function setupButton(buttonId) {
let clickCount = 0;
const button = document.getElementById(buttonId);
button.addEventListener('click', function () {
clickCount++;
console.log(`Кнопка нажата ${clickCount} раз`);
});
}
setupButton('myButton');
Пример
function createStore(initialState) {
let state = initialState;
const listeners = [];
return {
getState() {
return state;
},
setState(newState) {
state = newState;
listeners.forEach((listener) => listener(state));
},
subscribe(listener) {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
if (index > -1) listeners.splice(index, 1);
};
},
};
}
const store = createStore({ count: 0 });
store.subscribe((state) => {
console.log('Состояние изменено:', state);
});
store.setState({ count: 1 }); // Вывод: Состояние изменено: { count: 1 }
store.setState({ count: 2 }); // Вывод: Состояние изменено: { count: 2 }
Какие задачи в Nodejs выполняются в пуле потоков libuv
Операции с файловой системой (fs)
Криптографические операции (crypto)
Операции сжатия и распаковки данных (zlib)
Обработка с++ нативных модулей (add-ons)
Что является микротасками в js?
process.nextTick()
является микротаской, но с важным уточнением: она имеет более высокий приоритет, чем другие микротаски (такие как колбэки промисов).
Промисы (.then()
, .catch()
, .finally()
)
queueMicrotask() - 'это специальный метод для явного добавления задачи в очередь микротасков. Он был введён для случаев, когда вам нужно вручную добавить задачу в эту очередь, не используя промисы.
MutationObserver - это API для отслеживания изменений в DOM. Колбэк, переданный в MutationObserver
, добавляется в очередь микротасков и будет выполнен после того, как текущий цикл событий завершится.
Часть кода, которая выполняется после await
async function asyncTask() {
await Promise.resolve(console.log('Promise'));
console.log('Это микротаска от async/await');
}
asyncTask();
Правда ли, что Promise имеет асинхронное выполнение?
Создание промиса и его немедленная обработка — это синхронный процесс. Когда вы создаёте новый промис, его тело (executor) выполняется сразу, то есть синхронно.
Методы .then()
, .catch()
и .finally()
— это микротаски
Хотя создание промиса является синхронным, методы обработки результата промиса (.then()
, .catch()
, .finally()
) выполняются асинхронно и попадают в очередь микротасок.
Когда промис разрешается (выполняется resolve
или reject
), соответствующий колбэк (.then()
, .catch()
, .finally()
) добавляется в очередь микротасок и будет выполнен в следующем цикле событий, после того как завершится текущий синхронный код и все макротаски.
Какую память шарят воркер треды?
Каждый поток в Node.js, как правило, имеет собственное изолированное пространство памяти, но существуют механизмы для общего использования памяти между потоками.
SharedArrayBuffer (Общий буфер массива)
Основной механизм для разделения памяти между потоками в Node.js — это использование объекта SharedArrayBuffer
. SharedArrayBuffer
позволяет нескольким потокам одновременно иметь доступ к одному и тому же блоку памяти.
В этом примере создаётся SharedArrayBuffer
, который можно передавать между потоками (основным и воркер-тредом).
Оба потока могут одновременно читать и записывать данные в этот общий блок памяти.
Изменения, сделанные в одном потоке, сразу же видны в другом, потому что они работают с одним и тем же буфером в памяти.
Для чего нужны Stream в node js
Streams (потоки) в Node.js — это интерфейсы для работы с асинхронным вводом-выводом (I/O) в виде данных, которые поступают или отправляются постепенно, небольшими частями.
Какие типы потоков есть в NodeJs?
Readable (Читаемые потоки):
Потоки, из которых читаются данные. Пример: чтение данных из файла, HTTP-запроса, сетевого соединения.
Writable (Записываемые потоки):
Потоки, в которые можно записывать данные. Пример: запись данных в файл, отправка данных через HTTP-ответ.
Duplex (Дуплексные потоки):
Потоки, которые могут быть и читаемыми, и записываемыми. Пример: сетевые соединения, которые могут принимать и отправлять данные одновременно.
Transform (Трансформирующие потоки):
Специальный тип дуплексных потоков, которые могут модифицировать или трансформировать данные, проходящие через них. Пример: сжатие данных, шифрование, обработка данных в реальном времени.
Как потоки можно использовать в реальных задачах?
Чтение и запись файлов: Потоки часто используются для чтения и записи больших файлов, например, видео или лог-файлов, без необходимости загружать их целиком в память.
Работа с HTTP-запросами и ответами: В Node.js HTTP-запросы и ответы реализованы как потоки. Это позволяет эффективно обрабатывать данные, поступающие от клиента или отправляемые сервером, по частям.
Сжатие и обработка данных: Потоки можно использовать для сжатия файлов или данных "на лету", что снижает нагрузку на память и повышает производительность.
Стриминг мультимедиа: Потоки часто используются для стриминга мультимедийных данных (видео, аудио) по сети, так как они позволяют передавать данные небольшими частями, что ускоряет передачу и снижает нагрузку на память.
Как соеденить стримы правильно? Передавать данные из одного в другой
Использование pipe()
для соединения потоков
Для соединения потоков (стримов) в Node.js, используется метод pipe()
, который передаёт данные из одного потока в другой. Это наиболее правильный и эффективный способ передачи данных между потоками в Node.js. Метод pipe()
связывает читаемый поток (Readable Stream) с записываемым потоком (Writable Stream) и передаёт данные по мере их поступления.
const fs = require('fs');
const zlib = require('zlib');
// Создаём поток для чтения
const readableStream = fs.createReadStream('input.txt');
// Создаём поток для сжатия данных
const gzipStream = zlib.createGzip();
// Создаём поток для записи сжатых данных в файл
const writableStream = fs.createWriteStream('input.txt.gz');
// Соединяем потоки: чтение -> сжатие -> запись
readableStream.pipe(gzipStream).pipe(writableStream);
Объяснение:
Мы читаем данные из файла input.txt
с помощью fs.createReadStream()
.
Затем данные передаются в поток gzipStream
для сжатия данных с помощью zlib.createGzip()
.
Сжатые данные передаются в поток записи writableStream
, который записывает их в файл input.txt.gz
.
Использование pipeline()
для надёжного соединения потоков
Начиная с Node.js 10, был введён новый метод pipeline()
, который обеспечивает более надёжное соединение потоков и автоматически обрабатывает ошибки. Он является более удобным и безопасным вариантом по сравнению с ручным вызовом pipe()
и обработкой ошибок.
Преимущества pipeline()
:
Автоматическая обработка ошибок.
Удобный API для работы с несколькими потоками.
Надёжность: если один из потоков завершится с ошибкой, pipeline()
гарантирует корректное завершение всех потоков.