Irbisa · Шпаргалка
Продвинутый JavaScript
Приведение типов, call, apply и bind, оператор new, Map, Set и WeakMap, итераторы и генераторы, Proxy, сборка мусора, задачи «что выведет», свои Promise.all, curry и EventEmitter
В чём разница между
Mapи обычным объектом и междуSetи массивом?const user = { id: 7 }; const plain = {};plain[user] = 'Ada'; // the key becomes the string "[object Object]"plain[2] = 'two';plain.b = 'b';…Что такое
WeakMap,WeakSetиWeakRefи когда их использовать вместоMapиSet?// derived data per state object: entries go away together with old statesconst totals = new WeakMap(); function getTotal(cart) { if (!totals.has(cart)) { console.log('computing');…Чему равно каждое из этих выражений и какие правила приведения типов это объясняют?
console.log([] + {});console.log('5' - 2);console.log('5' + 2);console.log(true + 1);console.log(null + 1);console.log(undefined + 1);console.log([] == ![]);console.log('b' + 'a' + +'a' + 'a');Что делают
call,applyиbindи как написать полифил дляFunction.prototype.bind?Function.prototype.myBind = function (thisArg, ...preset) { const fn = this; return function bound(...args) { if (new.target) return new fn(...preset, ...args); // new ignores the bound this return fn.apply(thisArg, [...preset, ...args]); };…Что выведет этот код и почему
thisменяется от вызова к вызову?class Counter { count = 0; inc() { return ++this.count; } incArrow = () => ++this.count;} const c = new Counter();const other = { count: 10, inc: c.inc, incArrow: c.incArrow };console.log(c.inc());console.log(other.inc());console.log(other.incArrow());console.log(c.inc.bind(other).call(c));const { inc } = c;inc();Что по шагам делает оператор
newи как реализовать его заново обычной функцией?function myNew(Constructor, ...args) { const obj = Object.create(Constructor.prototype); // 1. link the prototype const result = Constructor.apply(obj, args); // 2. run the body with this = obj const isObject = result !== null && (typeof result === 'object' || typeof result === 'function'); return isObject ? result : obj; // 3. an object returned by the body wins}…Что делают
Object.freeze,Object.sealи дескрипторы свойств и почему замороженный объект не является глубоко неизменяемым?const config = Object.freeze({ api: '/v1', retry: { count: 3 } });config.retry.count = 5; // allowed: freeze is shallowtry { config.api = '/v2'; // modules and classes are strict, so this throws} catch (error) { console.log(error.message); // Cannot assign to read only property 'api' of object '#<Object>'…Что делает объект итерируемым, как работает
Symbol.iteratorи чемfor...ofотличается отfor...in?class Range { constructor(from, to) { this.from = from; this.to = to; }…Что такое функции-генераторы и где они до сих пор полезны во фронтенде?
function* idGenerator(prefix) { let n = 1; while (true) yield `${prefix}-${n++}`; // infinite, but lazy: runs only on next()} const ids = idGenerator('row');…Что выведет эта цепочка промисов и какой
thenилиcatchобработает каждую ошибку?Promise.resolve(1) .then((x) => { throw new Error(`boom ${x}`); }) .then((x) => console.log('a', x)) .catch((err) => err.message.toUpperCase()) .then( (x) => { console.log('b', x); throw new Error('again'); }, (err) => console.log('c', err.message), ) .finally(() => console.log('d')) .catch((err) => console.log('e', err.message));Что такое каррирование и как реализовать функцию
curry, которая поддерживает иsum(1)(2)(3), иsum(1, 2)(3)?function curry(fn) { return function curried(...args) { if (args.length >= fn.length) return fn.apply(this, args); return (...more) => curried.apply(this, [...args, ...more]); };}…Как написать функцию
memoizeи как не дать её кэшу расти бесконечно?function memoize(fn, { maxSize = 100, key = (...args) => JSON.stringify(args) } = {}) { const cache = new Map(); // a Map remembers insertion order: the first key is the oldest return function (...args) { const k = key(...args); if (cache.has(k)) {…Как реализовать
EventEmitterс методамиon,off,emitиonce?class EventEmitter { #listeners = new Map(); // event name -> array of listeners on(event, listener) { this.#listeners.set(event, [...(this.#listeners.get(event) ?? []), listener]); return () => this.off(event, listener); // handy as a useEffect cleanup…Как реализовать
Promise.allс нуля, сохранив порядок результатов и отклоняясь на первой ошибке?function promiseAll(iterable) { return new Promise((resolve, reject) => { const items = Array.from(iterable); const results = new Array(items.length); let pending = items.length; if (pending === 0) return resolve(results);…Как написать
retry(fn, attempts), которая повторяет упавший асинхронный вызов с экспоненциальной задержкой?const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function retry(fn, { attempts = 3, baseDelay = 200, maxDelay = 5000, shouldRetry = () => true } = {}) { for (let attempt = 1; ; attempt++) { try { return await fn(attempt); // without await, a rejection would skip this catch…Как выполнить список асинхронных задач так, чтобы одновременно выполнялось не больше N (пул промисов), и сохранить порядок результатов?
async function runPool(tasks, limit) { const results = new Array(tasks.length); let next = 0; // shared cursor: safe, because next++ runs without an await in between async function worker() { while (next < tasks.length) {…Что такое
Proxy, как его используют Immer, MobX и Vue и чего он стоит?// a tiny Vue-style reactive object: record reads, react to writesfunction reactive(target, onChange) { return new Proxy(target, { get(obj, key, receiver) { console.log('read', String(key)); // Vue's track(): remember who depends on key return Reflect.get(obj, key, receiver);…Как работает сборка мусора в движке JavaScript вроде V8 и как замыкание может случайно удержать в памяти большой объект?
// run with: node --expose-gc gc.jsconst handlers = []; function setup() { const report = new Array(1_000_000).fill(0); // about 8 MB const total = () => report.length; // the only closure that reads report…