JavaScript: различия между версиями

Материал из Artem Aleksashkin's Wiki
Перейти к навигации Перейти к поиску
(Новая страница: « * [https://www.youtube.com/watch?v=3kLS5UPvfss 16 САМЫХ ПОПУЛЯРНЫХ вопросов по JavaScript на собеседованиях] * [https://www.youtube.com/watch?v=p4PmANxsckA СОБЕСЕДОВАНИЕ FRONTEND ЗП 220к JS, TS задачи] * var, let, const ** var - объявляет или глобально или в теле функции ** let - объявляет в блоке кода {} ** const - как let, только...»)
 
 
(не показаны 3 промежуточные версии этого же участника)
Строка 1: Строка 1:
* [https://www.youtube.com/watch?v=3kLS5UPvfss 16 САМЫХ ПОПУЛЯРНЫХ вопросов по JavaScript на собеседованиях]
* [https://www.youtube.com/watch?v=3kLS5UPvfss 16 САМЫХ ПОПУЛЯРНЫХ вопросов по JavaScript на собеседованиях]
* [https://www.youtube.com/watch?v=p4PmANxsckA СОБЕСЕДОВАНИЕ FRONTEND ЗП 220к JS, TS задачи]
* [https://www.youtube.com/watch?v=p4PmANxsckA СОБЕСЕДОВАНИЕ FRONTEND ЗП 220к JS, TS задачи]
* var, let, const
 
= var, let, const =
** var - объявляет или глобально или в теле функции
** var - объявляет или глобально или в теле функции
** let - объявляет в блоке кода {}
** let - объявляет в блоке кода {}
Строка 21: Строка 21:
Object.freeze(obj);// замораживает объект
Object.freeze(obj);// замораживает объект
</pre>
</pre>
* Клонирование объектов
= Клонирование объектов =
** Поверхностная копия Shallow
** Поверхностная копия Shallow
*** Object.assign({}, objectToCopy)
*** Object.assign({}, objectToCopy)
Строка 40: Строка 40:
}
}
</pre>
</pre>
* Типы данных
= Типы данных =
** Number - целое или плав.точка или NaN typeof(value) === 'number'
* Number - целое или плав.точка или NaN typeof(value) === 'number'
** String - "Test", 'Test', `Test, ${test}` [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals] typeof(value) === 'string'
* String - "Test", 'Test', `Test, ${test}` [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals] typeof(value) === 'string'
** Boolean - true/false, typeof(value) === 'boolean'
* Boolean - true/false, typeof(value) === 'boolean'
** null - пустое значение, typeof(value) === 'object'
* null - пустое значение, typeof(value) === 'object'
** undefined - неопределенное значение, typeof(value) === 'undefined'
* undefined - неопределенное значение, typeof(value) === 'undefined'
** Symbol - уникальный тип данных, typeof(value) === 'symbol'
* Symbol - уникальный тип данных, typeof(value) === 'symbol'
** BigInt - произвольная точность или через конструктор или 12345n, typeof(value) === 'bigint'
* BigInt - произвольная точность или через конструктор или 12345n, typeof(value) === 'bigint'
** Object - или через конструктор или {}, typeof(value) === 'object'
* Object - или через конструктор или {}, typeof(value) === 'object'
** Array - или через конструктор или [], typeof(value) === 'object', Array.isArray(value) === true
* Array - или через конструктор или [], typeof(value) === 'object', Array.isArray(value) === true
** Function - или прямое объявление или через анонимную typeof(value) === 'function'
* Function - или прямое объявление или через анонимную typeof(value) === 'function'
** Date - new Date(), typeof(value) === 'object'
* Date - new Date(), typeof(value) === 'object'
** RegExp - или через new RegExp('^[a-z]*$', flags) или /^[a-z]*$/flags
* RegExp - или через new RegExp('^[a-z]*$', flags) или /^[a-z]*$/flags
** Map - карта - new Map(), map.set(key, value), typeof(map) === 'object'
* 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)
* Set - набор уникальных значений - new Set(array) или set.add(value), typeof(set) === 'object' set.has(val) -> O(1)
** WeakMap, WeakSet - Garbage Collector чистит значения, если исходные были удалены.
* WeakMap, WeakSet - Garbage Collector чистит значения, если исходные были удалены.
* Garbage Collector
 
** Mark(пометка недостижимых объектов) & Sweap(удаление)
= Garbage Collector =
* Function Declaration и Function Expression
 
** Function Declaration
* Mark(пометка недостижимых объектов) & Sweap(удаление)
 
= Function Declaration и Function Expression =
* Function Declaration
<pre>
<pre>
console.log(factorial(5));// функция всплывает
console.log(factorial(5));// функция всплывает
Строка 71: Строка 74:
</pre>
</pre>


** Function Expression
* Function Expression
<pre>
<pre>
const factorial = function factorial(n) {
const factorial = function factorial(n) {
Строка 82: Строка 85:
console.log(factorial(5));// функция не всплывает
console.log(factorial(5));// функция не всплывает
</pre>
</pre>
* Function Generator
 
= Function Generator =
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*]
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*]
<pre>
<pre>
Строка 94: Строка 98:
console.log(gen.next());// {value: 1, done: false}
console.log(gen.next());// {value: 1, done: false}
</pre>
</pre>
* Arrow Function
= Arrow Function =
<pre>
<pre>
() => expression
() => expression
Строка 111: Строка 115:
</pre>
</pre>


== this ==
= this =
* this - контекст, которым можно манипулировать. ([https://www.youtube.com/live/4tg4qokVS9o Как работает this в javascript. Разберемся на примерах опираясь на официальную спецификацию])
* this - контекст, которым можно манипулировать. ([https://www.youtube.com/live/4tg4qokVS9o Как работает this в javascript. Разберемся на примерах опираясь на официальную спецификацию])
** bind(thisArg, arg1, arg2, /* …, */ argN)
** bind(thisArg, arg1, arg2, /* …, */ argN)
Строка 141: Строка 145:
** у module - this undefined
** у module - this undefined


== dot нотация ==
= dot нотация =


У JavaScript есть 2 способа обращаться к свойствам объекта.
У JavaScript есть 2 способа обращаться к свойствам объекта.
Строка 152: Строка 156:
Obj["theFunc"]();
Obj["theFunc"]();


== modules ==
= modules =


* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
Строка 182: Строка 186:
модули можно хранить в *.mjs или *.js файлах
модули можно хранить в *.mjs или *.js файлах


== Сравнение ==
= Сравнение =


<gallery>
<gallery>
Строка 196: Строка 200:
* Array.isArray() [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray]
* Array.isArray() [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray]


== Замыкание(Closure) ==
= Замыкание(Closure) =


https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Строка 204: Строка 208:
Я никогда не понимал почему это назвали замыканием. Я бы назвал - ближайшее окружение.
Я никогда не понимал почему это назвали замыканием. Я бы назвал - ближайшее окружение.


== Асинхронность ==
= Асинхронность =


[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise]
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise]
Строка 258: Строка 262:
</pre>
</pre>


* Async Await
== Async Await ==


<pre>
<pre>
Строка 304: Строка 308:
</pre>
</pre>


== Prototype ==
= Prototype =


Прототипы позволяют организовать прототипное наследование
Прототипы позволяют организовать прототипное наследование
Строка 347: Строка 351:
Метод Object.hasOwnProperty проверяет, является ли свойство собственным свойством объекта. Он не учитывает свойства, унаследованные по цепочке прототипов.
Метод Object.hasOwnProperty проверяет, является ли свойство собственным свойством объекта. Он не учитывает свойства, унаследованные по цепочке прототипов.


== Debounce, throttle, curry ==
= Debounce, throttle, curry =
<pre>
<pre>
function debounce(func, wait) {
function debounce(func, wait) {

Текущая версия от 20:12, 11 ноября 2024

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
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

[2]

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

Привязка контекста к функции

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 файлах

Сравнение

Также есть

  • Object.is() [3]
  • Number.isNaN() [4]
  • Array.isArray() [5]

Замыкание(Closure)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

Это функция, которая сохраняет доступ к переменным из своего внешнего окружения, даже после того как это окружение перестало существовать.

Я никогда не понимал почему это назвали замыканием. Я бы назвал - ближайшее окружение.

Асинхронность

[6]

Метод "в лоб"

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!
Js-prototype.png

Метод 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