JavaScript
- 16 САМЫХ ПОПУЛЯРНЫХ вопросов по JavaScript на собеседованиях
- СОБЕСЕДОВАНИЕ FRONTEND ЗП 220к JS, TS задачи
- var, let, const
- var - объявляет или глобально или в теле функции
- let - объявляет в блоке кода {}
- const - как let, только нельзя менять ссылку на объект
- Блокировка изменения объекта
let obj = {}; Object.defineProperty(obj, 'name', { value: 'John', writable: false,// можно ли изменять enumerable: true,// можно ли перечислять в циклах configurable: false// можно ли изменять другие дескрипторы, удалять или менять тип свойства });
Object.preventExtensions(obj); //запретит добавлять новые свойства Object.seal(obj);//запретит добавлять, удалять, но позволяет менять изменять свойства Object.freeze(obj);// замораживает объект
- Клонирование объектов
- Поверхностная копия Shallow
- Object.assign({}, objectToCopy)
- {...objectToCopy} - спред оператор
- Глубока Deep
- JSON.parse(JSON.stringify(objectToCopy))
- structuredClone(objectToCopy);
- https://lodash.com/docs/4.17.15#cloneDeep _.cloneDeep(objectToCopy);
- Поверхностная копия Shallow
function deepClone(value) { if (typeof value !== 'object' || value === null) { return value; } if (Array.isArray(value)) { return value.map((item) => deepClone(item)); } return Object.fromEntries(Object.entries(value).map(([key, value]) => [key, deepClone(value)])); }
- Типы данных
- Number - целое или плав.точка или NaN typeof(value) === 'number'
- String - "Test", 'Test', `Test, ${test}` [1] typeof(value) === 'string'
- Boolean - true/false, typeof(value) === 'boolean'
- null - пустое значение, typeof(value) === 'object'
- undefined - неопределенное значение, typeof(value) === 'undefined'
- Symbol - уникальный тип данных, typeof(value) === 'symbol'
- BigInt - произвольная точность или через конструктор или 12345n, typeof(value) === 'bigint'
- Object - или через конструктор или {}, typeof(value) === 'object'
- Array - или через конструктор или [], typeof(value) === 'object', Array.isArray(value) === true
- Function - или прямое объявление или через анонимную typeof(value) === 'function'
- Date - new Date(), typeof(value) === 'object'
- RegExp - или через new RegExp('^[a-z]*$', flags) или /^[a-z]*$/flags
- Map - карта - new Map(), map.set(key, value), typeof(map) === 'object'
- Set - набор уникальных значений - new Set(array) или set.add(value), typeof(set) === 'object' set.has(val) -> O(1)
- WeakMap, WeakSet - Garbage Collector чистит значения, если исходные были удалены.
- Garbage Collector
- Mark(пометка недостижимых объектов) & Sweap(удаление)
- Function Declaration и Function Expression
- Function Declaration
console.log(factorial(5));// функция всплывает function factorial(n) { if (n <= 1) { return 1; } return n * factorial(n - 1); }
- Function Expression
const factorial = function factorial(n) { if (n <= 1) { return 1; } return n * factorial(n - 1); }; console.log(factorial(5));// функция не всплывает
- Function Generator
function* generatorFunction() { yield 1; yield 2; return 3; } const gen = generatorFunction(); console.log(gen.next());// {value: 1, done: false}
- Arrow Function
() => expression param => expression (param) => expression (param1, paramN) => expression () => { statements } param => { statements } (param1, paramN) => { statements }
this
- this - контекст, которым можно манипулировать. (Как работает this в javascript. Разберемся на примерах опираясь на официальную спецификацию)
- bind(thisArg, arg1, arg2, /* …, */ argN)
Привязка контекста к функции
let user = { firstName: "Вася", sayHi() { alert(`Привет, ${this.firstName}!`); } }; let sayHi = user.sayHi.bind(user); // (*) sayHi(); // Привет, Вася! setTimeout(sayHi, 1000); // Привет, Вася!
- call, apply - вызывает функцию с контекстом
func.call(context, arg1, arg2); // идентичен вызову func.apply(context, [arg1, arg2]);
- arguments
- у new Function() this - {} - пустой объект
- у ArrowFunction контекст берется из окружения, изменить его нельзя. arguments не передается
- у global - this глобальный объект
- у module - this undefined
dot нотация
У JavaScript есть 2 способа обращаться к свойствам объекта.
Через точку Obj.theProperty и через строчку Obj["theProperty"] - это идентично.
Функции объекта вызываются аналогично
Obj.theFunc(); Obj["theFunc"]();
modules
Позволяет разделить код на модули
export const name = "square"; export function draw(ctx, length, x, y, color) { ctx.fillStyle = color; ctx.fillRect(x, y, length, length); return { length, x, y, color }; }
и потом их импортировать
import { name, draw, reportArea, reportPerimeter } from "./modules/square.js";
экспорт можно прописать отдельной инструкцией
export { name, draw, reportArea, reportPerimeter };
модули можно хранить в *.mjs или *.js файлах
Сравнение
Также есть
Замыкание(Closure)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Это функция, которая сохраняет доступ к переменным из своего внешнего окружения, даже после того как это окружение перестало существовать.
Я никогда не понимал почему это назвали замыканием. Я бы назвал - ближайшее окружение.
Асинхронность
Метод "в лоб"
function doSomethingAsync(callback) { setTimeout(() => { callback(); }); } doSomethingAsync(() => { console.log('async code'); });
- Promise
- Pending
- Fulfilled
- Rejected
- Promise.all() - принимает массив, возвращает промис с выполненными промисами или одну ошибку
- Promise.allSettled() - принимает массив, возвращает промис с результатами
- Promise.any() - принимает массив, возвращает результат любого успешного промиса или ошибку в случае безуспешного результата
- Promise.race() - принимает массив, возвращает результат первого промиса или ошибку
- Promise.reject()
- Promise.resolve()
- Promise.try()
- Promise.withResolvers()
function checkMail() { return new Promise((resolve, reject) => { if (Math.random() > 0.5) { resolve('Mail has arrived'); } else { reject(new Error('Failed to arrive')); } }); } checkMail() .then((mail) => { console.log(mail); }) .catch((err) => { console.error(err); }) .finally(() => { console.log('Experiment completed'); });
- Async Await
function resolveAfter2Seconds() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('resolved'); }, 2000); }); } async function asyncCall() { console.log('calling'); const result = await resolveAfter2Seconds().catch((value) => {console.error(value);}).finally(() => {console.log('finally');}); console.log(result); // Expected output: "resolved" } asyncCall();
- Observable RxJS [7]
function checkMail() { return new Observable((subscriber: Subscriber<string | null>) => { if (Math.random() > 0.5) { subscriber.next('next'); } else { subscriber.complete(); // subscriber.error(new Error('12345')); // subscriber.unsubscribe(); } }); } checkMail() .subscribe({ next: (results: string | null): void => { console.log(results); }, error: (err) => console.error('something wrong occurred: ', err), complete: () => { console.log('complete'); }, });
Prototype
Прототипы позволяют организовать прототипное наследование
function Person(name) { this.name = name; } Person.prototype.greet = function() { console.log(`Hello, my name is ${this.name}!`); } const john = new Person('John'); john.greet(); // Hello, my name is John
Вытащить прототип объекта (getPrototypeOf или __proto__(устар))
const obj = {}; console.log(obj.toString());// [object Object] console.log(Object.getPrototypeOf(obj) === Object.prototype);// true console.log(Object.getPrototypeOf(obj.prototype) === null);// true
Установить прототип
const proto = { greet: function() { console.log('Hello!'); } }; const obj = {}; Object.setPrototypeOf(obj, proto); obj.greet(); // Hello!
Метод Object.hasOwn проверяет наличие собственного свойства у объекта.
Метод Object.hasOwnProperty проверяет, является ли свойство собственным свойством объекта. Он не учитывает свойства, унаследованные по цепочке прототипов.
Debounce, throttle, curry
function debounce(func, wait) { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } // Пример использования window.addEventListener('resize', debounce(() => { console.log('Resize event'); }, 200));
function throttle(func, limit) { let lastFunc; let lastRan; return function(...args) { const context = this; if (!lastRan) { func.apply(context, args); lastRan = Date.now(); } else { clearTimeout(lastFunc); lastFunc = setTimeout(function() { if ((Date.now() - lastRan) >= limit) { func.apply(context, args); lastRan = Date.now(); } }, limit - (Date.now() - lastRan)); } }; } // Пример использования window.addEventListener('scroll', throttle(() => { console.log('Scroll event'); }, 200));
function curry(func) { return function curried(...args) { if (args.length >= func.length) { return func.apply(this, args); } else { return function(...nextArgs) { return curried.apply(this, args.concat(nextArgs)); }; } }; } // Пример использования function sum(a, b, c) { return a + b + c; } const curriedSum = curry(sum); console.log(curriedSum(1)(2)(3)); // 6 console.log(curriedSum(1, 2)(3)); // 6 console.log(curriedSum(1, 2, 3)); // 6
function partial(func, ...fixedArgs) { return function(...args) { return func.apply(this, fixedArgs.concat(args)); }; } const add = (a, b, c) => a + b + c; const add5 = partial(add, 5); console.log(add5(10, 15)); // 30
Event Loop
- Стек вызовов (Call stack) - структура данных, где хранятся текущие выполняющиеся функции. Когда функция вызывается, она добавляется в стек вызовов, когда её выполнение завершается, она удаляется из стека вызовов.
- Web API - браузер предоставляет различные API для создания веб-приложений (DOM API, Storage API, XMLHttpRequest)
- Очередь тасок (Task queue) - очередь, куда попадают задачи от Web API
- Очередь микротасок (Microtask queue) - очередь, куда попадают задачи от промисов, MutationObserver, IntersectionObserver, queueMicrotask(),
Алгоритм работы
- Выполнить все синхронные задачи, задачи с Web API отдать на выполнение браузеру.
- Выполнить все задачи из очереди микротасок (выполняются, пока очередь не опустеет)
- Выполнить одну макротаску из очереди макротасок
- Произвести рендеринг
- Начать с 1 шага
const myFn = async() => { console.log("1");// -> Call stack setTimeout(() => console.log("6"));// -> Task queue Promise.resolve().then(() => console.log("4"));// -> Microtask queue console.log("2");// -> Call stack await Promise.resolve();// -> Microtask queue console.log("5");// -> Microtask queue } myFn(); console.log("3");// -> Call stack // Call stack // Microtask queue // Task queue 1 2 3 4 5 6
- requestAnimationFrame
- requestIdleCallback