— подписывайтесь на меня на github
Вопросы
- 1. В чем разница между
undefined
иnull
? - 2. Что делает оператор &&?
- 3. Что означает || оператор делать?
- 4. Является ли использование оператора + или унарного плюса самым быстрым способом преобразования строки в число?
- 5. Что такое ДОМ?
- 6. Что такое распространение событий?
- 7. Что такое пузырьковое событие?
- 8. Что такое захват событий?
- 9. В чем разница между методами
event.preventDefault()
иevent.stopPropagation()
? - 10. Как узнать, использовался ли в элементе метод
event.preventDefault()
? - 11. Почему этот код obj.someprop.x выдает ошибку?
- 12. Что такое event.target?
- 13. Что такое event.currentTarget?
- 14. В чем разница между
==
и===
? - 15. Почему он возвращает false при сравнении двух похожих объектов в JavaScript?
- 16. Что делает оператор
!!
? - 17. Как вычислить несколько выражений в одной строке?
- 18. Что такое подъем?
- 19. Что такое объем?
- 20. Что такое замыкания?
- 21. Что такое ложные значения в JavaScript?
- 22. Как проверить, является ли значение ложным?
- 23. Что делает
"use strict"
? - 24. Каково значение
this
в JavaScript? - 25. Что такое
prototype
объекта? - 26. Что такое IIFE, какая от него польза?
- 27. Как использовать
Function.prototype.apply
метод? - 28. Как использовать
Function.prototype.call
метод? - 29. В чем разница между
Function.prototype.apply
иFunction.prototype.call
? - 30. Каково использование
Function.prototype.bind
? - 31. Что такое функциональное программирование и какие особенности JavaScript делают его кандидатом на роль функционального языка?
- 32. Что такое функции высшего порядка?
- 33. Почему функции называются первоклассными объектами?
- 34. Реализуйте метод
Array.prototype.map
вручную. - 35. Реализуйте метод
Array.prototype.filter
вручную. - 36. Реализуйте метод
Array.prototype.reduce
вручную. - 37. Что такое объект
arguments
? - 38. Как создать объект без прототипа?
- 39. Почему
b
в этом коде становится глобальной переменной при вызове этой функции? - 40. Что такое ECMAScript?
- 41. Какие новые функции появились в ES6 или ECMAScript 2015?
- 42. В чем разница между ключевыми словами
var
,let
иconst
? - 43. Что такое Стрелочные функции?
- 44. Что такое Курсы?
- 45. Что такое литералы шаблонов?
- 46. Что такое Деструктуризация объектов?
- 47. Что такое
ES6 Modules
? - 48. Что такое объект
Set
и как он работает? - 49. Что такое функция обратного вызова?
- 50. Что такое обещания?
- 51. Что такое async/await и как это работает?
- 52. В чем разница между оператором Spread и оператором Rest?
- 53. Что такое параметры по умолчанию?
- 54. Что такое Объекты-оболочки?
- 55. В чем разница между неявным и явным принуждением?
- 56. Что такое
NaN
? и Как проверить, является ли значениеNaN
? - 57. Как проверить, является ли значение массивом?
- 58. Как проверить, является ли число четным, без использования оператора
%
или по модулю? - 59. Как проверить, существует ли определенное свойство в объекте?
- 60. Что такое AJAX?
- 61. Какие есть способы создания объектов в JavaScript?
- 62. В чем разница между методами
Object.seal
иObject.freeze
? - 63. В чем разница между оператором
in
и методомhasOwnProperty
в объектах? - 64. Как справиться с асинхронным кодом в JavaScript?
- 65. В чем разница между выражением функции и объявлением функции?
- «66. Сколько способов вызвать функцию?"
- 67. Что такое запоминание и в чем его польза?
- 68. Реализуйте вспомогательную функцию запоминания.
- 69. Почему
typeof null
возвращаетobject
? Как проверить, является ли значениеnull
? - 70. Что делает ключевое слово
new
?
1. В чем разница между undefined
и null
?
↑ Прежде чем понять разницу между undefined
и null
, мы должны понять сходство между ними.
- Они относятся к 7 примитивным типам JavaScript.
let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];
- Это ложные значения. Значения, которые оцениваются как ложные при преобразовании в логическое значение с использованием
Boolean(value)
или!!value
.
console.log(!!null); //logs false console.log(!!undefined); //logs false
console.log(Boolean(null)); //logs false console.log(Boolean(undefined)); //logs false
Хорошо, давайте поговорим об отличиях.
undefined
— это значение по умолчанию для переменной, которой не присвоено конкретное значение. Или функция, которая не имеет явного возвращаемого значения, например.console.log(1)
. Или свойство, которого нет в объекте. Механизм JavaScript делает это за нас, назначая значениеundefined
.
let _thisIsUndefined; const doNothing = () => {}; const someObj = { a : "ay", b : "bee", c : "si" };
console.log(_thisIsUndefined); //logs undefined console.log(doNothing()); //logs undefined console.log(someObj["d"]); //logs undefined
null
— это 'значение, которое не представляет никакого значения'.null
– это значение, которое было явно определено для переменной. В этом примере мы получаем значениеnull
, когда методfs.readFile
не выдает ошибку.
fs.readFile('path/to/file', (e,data) => {
console.log(e); //it logs null when no error occurred
if(e){
console.log(e);
}
console.log(data);
});
При сравнении null
и undefined
мы получаем true
при использовании ==
и false
при использовании ===
. О причине можно прочитать здесь.
console.log(null == undefined); // logs true
console.log(null === undefined); // logs false
2. Что делает оператор &&
?
↑ Оператор &&
или Логическое И находит первое ложное выражение в своих операндах и возвращает его, а если не находит ни одного ложного выражения он возвращает последнее выражение. Он использует короткое замыкание, чтобы предотвратить ненужную работу. Я использовал это в блоке catch
при закрытии соединения с базой данных в одном из моих проектов.
console.log(false && 1 && []); //logs false
console.log(" " && true && 5); //logs 5
Использование операторов if.
const router: Router = Router();
router.get('/endpoint', (req: Request, res: Response) => { let conMobile: PoolConnection; try { //do some db operations } catch (e) { if (conMobile) { conMobile.release(); } } });
Использование оператора &&.
const router: Router = Router();
router.get('/endpoint', (req: Request, res: Response) => { let conMobile: PoolConnection; try { //do some db operations } catch (e) { conMobile && conMobile.release() } });
3. Что делает оператор ||
?
↑ Оператор ||
или логическое ИЛИ находит первое истинное выражение в своих операндах и возвращает его. Это также использует короткое замыкание, чтобы предотвратить ненужную работу. Раньше он использовался для инициализации значений параметров по умолчанию в функциях до поддержки параметров функций по умолчанию ES6.
console.log(null || 1 || undefined); //logs 1
function logName(name) { var n = name || "Mark"; console.log(n); }
logName(); //logs "Mark"
4. Является ли использование оператора + или унарного плюса самым быстрым способом преобразования строки в число?
↑ Согласно Документации MDN +
— это самый быстрый способ преобразования строки в число, поскольку он не выполняет никаких операций над значением, если оно уже является числом.
5. Что такое ДОМ?
↑ DOM означает Объектная модель документа — это интерфейс (API) для документов HTML и XML. Когда браузер впервые читает (разбирает) наш HTML-документ, он создает большой объект, действительно большой объект на основе HTML-документа, это DOM. Это древовидная структура, созданная на основе HTML-документа. DOM используется для взаимодействия и изменения структуры DOM или отдельных элементов или узлов.
Представьте, что у нас есть такая структура HTML.
<!DOCTYPE html> <html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document Object Model</title> </head>
<body> <div> <p> <span></span> </p> <label></label> <input> </div> </body>
</html>
Эквивалент DOM будет таким.
Объект document
в JavaScript представляет DOM. Он предоставляет нам множество методов, которые мы можем использовать для выбора элементов, обновления содержимого элементов и многого другого.
6. Что такое распространение событий?
↑ Когда событие происходит с элементом DOM, это событие не происходит полностью с одним этим элементом. На фазе всплытия событие всплывает или переходит к своему родителю, к бабушке и дедушке, к родителю бабушки и дедушки, пока не достигнет window
, находясь в Фаза захвата событие начинается с window
до элемента, вызвавшего событие, или event.target
.
Распространение событий состоит из трех этапов.
- Фаза захвата — событие начинается с
window
, затем переходит к каждому элементу, пока не достигнет целевого элемента. - Целевая фаза — событие достигло целевого элемента.
- Фаза всплытия — событие всплывает вверх от целевого элемента, затем поднимается вверх по каждому элементу, пока не достигнет
window
.
7. Что такое пузыри событий?
↑ Когда событие происходит с элементом DOM, это событие не происходит полностью с одним этим элементом. На этапе всплытия событие всплывает или переходит к своему родителю, к бабушке и дедушке, к родителю бабушки и дедушки, пока не достигнет window
.
Если у нас есть пример такой разметки.
<div class="grandparent">
<div class="parent">
<div class="child">1</div>
</div>
</div>
И наш js-код.
function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); }
addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent');
addEvent(child, 'click', function (e) { console.log('child'); });
addEvent(parent, 'click', function (e) { console.log('parent'); });
addEvent(grandparent, 'click', function (e) { console.log('grandparent'); });
addEvent(document, 'click', function (e) { console.log('document'); });
addEvent('html', 'click', function (e) { console.log('html'); })
addEvent(window, 'click', function (e) { console.log('window'); })
});
Метод addEventListener
имеет третий необязательный параметр useCapture со значением по умолчанию false
, событие произойдет на фазе всплытия, если true
событие произойдет на этапе захвата . Если мы нажмем на элемент child
, он зарегистрирует child
, parent
, grandparent
, html
, document
и window
соответственно на консоли. Это Всплывающие события.
8. Что такое захват событий?
↑ Когда событие происходит с элементом DOM, это событие не происходит полностью с одним этим элементом. На этапе захвата событие начинается с window
вплоть до элемента, вызвавшего событие.
Если у нас есть пример такой разметки.
<div class="grandparent">
<div class="parent">
<div class="child">1</div>
</div>
</div>
И наш js-код.
function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); }
addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent');
addEvent(child, 'click', function (e) { console.log('child'); }, true);
addEvent(parent, 'click', function (e) { console.log('parent'); }, true);
addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }, true);
addEvent(document, 'click', function (e) { console.log('document'); }, true);
addEvent('html', 'click', function (e) { console.log('html'); }, true)
addEvent(window, 'click', function (e) { console.log('window'); }, true)
});
Метод addEventListener
имеет третий необязательный параметр useCapture со значением по умолчанию false
событие произойдет на этапе всплытия, если true
событие произойдет на этапе захвата . Если мы нажмем на элемент child
, он зарегистрирует window
, document
, html
, grandparent
и parent
и child
соответственно на консоли. Это фиксация событий.
9. В чем разница между методами event.preventDefault()
и event.stopPropagation()
?
↑ Метод event.preventDefault()
предотвращает поведение элемента по умолчанию. Если он используется в элементе form
, он предотвращает его отправку. Если он используется в элементе anchor
, он предотвращает навигацию по нему. При использовании в contextmenu
он предотвращает его отображение или отображение. В то время как метод event.stopPropagation()
останавливает распространение события или предотвращает возникновение события на этапе пузырькового или захвата.
10. Как узнать, использовался ли в элементе метод event.preventDefault()
?
↑ Мы можем использовать свойство event.defaultPrevented
в объекте события. Он возвращает boolean
, указывающий, был ли вызван event.preventDefault()
в конкретном элементе.
11. Почему этот код obj.someprop.x
выдает ошибку?
const obj = {};
console.log(obj.someprop.x);
↑Очевидно, что это выдает ошибку из-за того, что мы пытаемся получить доступ к свойству x
в свойстве someprop
, имеющем значение undefined
. Помните, что свойства в объекте, который не существует сам по себе, и его прототип имеет значение по умолчанию undefined
, а undefined
не имеет свойства x
.
12. Что такое event.target?
↑ Проще говоря, event.target — это элемент, для которого произошло событие, или элемент, который инициировал событие.
Пример HTML-разметки.
<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
<div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
<div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
<button style="margin:10px">
Button
</button>
</div>
</div>
</div>
Пример JavaScript.
function clickFunc(event) {
console.log(event.target);
}
Если вы нажмете кнопку, она зарегистрирует разметку кнопки, даже если мы прикрепим событие к самому внешнему div
, она всегда будет записывать кнопку, поэтому мы можем сделать вывод, что event.target — это элемент, вызвавший событие.
13. Что такое event.currentTarget?
↑ event.currentTarget — это элемент, к которому мы прикрепляем обработчик события явно.
Копирование разметки в Вопросе 12.
Пример разметки HTML.
<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
<div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
<div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
<button style="margin:10px">
Button
</button>
</div>
</div>
</div>
И немного изменим наш JS.
function clickFunc(event) {
console.log(event.currentTarget);
}
Если вы нажмете кнопку, она зарегистрирует самую внешнюю разметку div, даже если мы нажмем кнопку. В этом примере мы можем сделать вывод, что event.currentTarget — это элемент, к которому мы прикрепляем обработчик событий.
14. В чем разница между ==
и ===
?
↑ Разница между ==
(абстрактное равенство) и ===
(строгое равенство) заключается в том, что ==
сравнивается по значению после приведения и ===
сравниваются по значению и типу без принуждения.
Давайте углубимся в ==
. Итак, сначала давайте поговорим о принуждении.
приведение — это процесс преобразования значения в другой тип. Как и в этом случае, ==
выполняет неявное приведение. У ==
есть несколько условий, которые необходимо выполнить перед сравнением двух значений.
Предположим, нам нужно сравнить x == y
значений.
- Если
x
иy
имеют одинаковый тип. Затем сравните их с оператором===
. - Если
x
равноnull
, аy
равноundefined
, вернутьtrue
. - Если
x
равноundefined
, аy
равноnull
, вернутьtrue
. - Если
x
относится к типуnumber
, аy
к типуstring
, то возвращаемx == toNumber(y)
. - Если
x
относится к типуstring
, аy
к типуnumber
, то вернитеtoNumber(x) == y
. - Если
x
имеет типboolean
, то вернутьtoNumber(x) == y
. - Если
y
имеет типboolean
, то вернутьx == toNumber(y)
. - Если
x
равноstring
,symbol
илиnumber
, аy
имеет типobject
, то вернутьx == toPrimitive(y)
. - Если
x
равноobject
, аx
равноstring
,symbol
, то вернутьtoPrimitive(x) == y
. - Вернуть
false
.
Примечание. toPrimitive
сначала использует метод valueOf
, а затем метод toString
в объектах, чтобы получить примитивное значение этого объекта.
Давайте примеры.
x
y
x == y
5
5
true
1
'1'
true
null
undefined
true
0
false
true
'1,2'
[1,2]
true
'[object Object]'
{}
true
Все эти примеры возвращают true
.
Первый пример соответствует условию номер один, потому что x
и y
имеют одинаковый тип и значение.
Второй пример соответствует четвертому условию y
перед сравнением преобразуется в number
.
Третий пример соответствует второму условию.
Четвертый пример соответствует седьмому условию, потому что y
равно boolean
.
Пятый пример относится к условию восемь. Массив преобразуется в string
с помощью метода toString()
, который возвращает 1,2
.
Последний пример относится к десятому условию. Объект преобразуется в string
с помощью метода toString()
, который возвращает [object Object]
.
x
y
x === y
5
5
true
1
'1'
false
null
undefined
false
0
false
false
'1,2'
[1,2]
false
'[object Object]'
{}
false
Если мы используем оператор ===
, все сравнения, кроме первого примера, вернут false
, потому что они не имеют одного и того же типа, а первый пример вернет true
, потому что они имеют одинаковый тип и значение.
15. Почему он возвращает false при сравнении двух похожих объектов в JavaScript?
↑ Допустим, у нас есть пример ниже.
let a = { a: 1 }; let b = { a: 1 }; let c = a;
console.log(a === b); // logs false even though they have the same property console.log(a === c); // logs true hmm
JavaScript по-разному сравнивает объекты и примитивы. В примитивах они сравниваются по значению, а в объектах сравниваются по ссылке или адресу в память, в которой хранится переменная. Вот почему первый оператор console.log
возвращает false
, а второй оператор console.log
возвращает true
. a
и c
имеют одинаковую ссылку, а a
и b
- разные.
16. Что означает !! оператор делать?
↑ Оператор Double NOT или !! преобразует значение справа в логическое значение. в основном это причудливый способ преобразования значения в логическое значение.
console.log(!!null); //logs false
console.log(!!undefined); //logs false
console.log(!!''); //logs false
console.log(!!0); //logs false
console.log(!!NaN); //logs false
console.log(!!' '); //logs true
console.log(!!{}); //logs true
console.log(!![]); //logs true
console.log(!!1); //logs true
console.log(!![].length); //logs false
17. Как вычислить несколько выражений в одной строке?
↑ Мы можем использовать оператор ,
или запятую для оценки нескольких выражений в одной строке. Он оценивается слева направо и возвращает значение последнего элемента справа или последнего операнда.
let x = 5;
x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10);
function addFive(num) { return num + 5; }
Если вы запишете значение x
, оно будет 27. Во-первых, мы увеличиваем значение x, оно должно быть 6, затем мы вызываем функцию addFive(6)
и передаем 6 в качестве параметра и присваиваем результат x
новому значению x
будет 11. После этого мы умножаем текущее значение x
на 2 и назначаем его x
обновленное значение x
будет 22. Затем мы вычитаем текущее значение x
из 5 и присваиваем результат x
, обновленное значение будет 17. И, наконец, мы увеличиваем значение x
на 10 и присваиваем обновленное значение x
, теперь значение x
будет 27.
18. Что такое подъем?
↑ Поднятие – это термин, используемый для описания перемещения переменных и функций наверх их (глобальных или функциональных) область, где мы определяем эту переменную или функцию.
Хорошо, чтобы понять Поднятие, мне нужно объяснить контекст выполнения.
Контекст выполнения — это «среда кода», которая в настоящее время выполняется. Контекст выполнения состоит из двух фаз: компиляция и выполнение.
Компиляция — на этом этапе он получает все объявления функций и поднимает их в верхнюю часть своей области, чтобы мы могли ссылаться на них позже, и получает все объявление переменных (объявить с помощью ключевого слова var), а также поднимает их и присваивает им значение по умолчанию undefined.
Выполнение — на этом этапе он присваивает значения переменным, поднятым ранее, и выполняет или вызывает функции (методы в объектах).
Примечание. подняты только объявления функций и переменные, объявленные с помощью ключевого слова var, а не функциональные выражения или стрелочные функции, ключевые слова let
и const
.
Хорошо, предположим, что у нас есть пример кода в глобальной области ниже.
console.log(y); y = 1; console.log(y); console.log(greet("Mark"));
function greet(name){ return 'Hello ' + name + '!'; }
var y;
Этот код регистрирует undefined
, 1
, Hello Mark!
соответственно.
Таким образом, этап компиляции будет выглядеть следующим образом.
function greet(name) { return 'Hello ' + name + '!'; }
var y; //implicit "undefined" assignment
//waiting for "compilation" phase to finish
//then start "execution" phase /* console.log(y); y = 1; console.log(y); console.log(greet("Mark")); */
например, я прокомментировал назначение переменной и вызов функции.
После завершения этапа компиляции начинается этап выполнения, вызывающий методы и присваивающий значения переменным.
function greet(name) { return 'Hello ' + name + '!'; }
var y;
//start "execution" phase
console.log(y); y = 1; console.log(y); console.log(greet("Mark"));
19. Что такое объем?
↑ Область в JavaScript — это область, в которой у нас есть действительный доступ к переменным или функциям. В JavaScript есть три типа областей видимости. Глобальная область, Область действия и Область действия блока (ES6).
- Глобальная область действия — переменные или функции, объявленные в глобальном пространстве имен, находятся в глобальной области видимости и, следовательно, доступны в любом месте нашего кода.
//global namespace var g = "global";
function globalFunc(){ function innerFunc(){ console.log(g); // can access "g" because "g" is a global variable } innerFunc(); }
- Область действия — переменные, функции и параметры, объявленные внутри функции, доступны внутри этой функции, но не за ее пределами.
function myFavoriteFunc(a) { if (true) { var b = "Hello " + a; } return b; } myFavoriteFunc("World");
console.log(a); // Throws a ReferenceError "a" is not defined console.log(b); // does not continue here
- Область блока — переменные (
let
,const
), объявленные в блоке{}
, могут быть доступны только внутри него.
function testBlock(){ if(true){ let z = 5; } return z; }
testBlock(); // Throws a ReferenceError "z" is not defined
Область действия — это также набор правил для поиска переменных. Если переменная не существует в текущей области, она ищет и ищет переменную в внешней области, и если не существует снова, она ищет снова, пока не достигнет глобальной области действия, если переменная существует, мы можем ее использовать, если нет, она выдает ошибку. Он ищет ближайшую переменную и прекращает поиск или поиск вверх, как только находит ее. Это называется цепочка областей действия.
/* Scope Chain Inside inner function perspective
inner's scope -> outer's scope -> global's scope */
//Global Scope var variable1 = "Comrades"; var variable2 = "Sayonara";
function outer(){ //outer's scope var variable1 = "World"; function inner(){ //inner's scope var variable2 = "Hello"; console.log(variable2 + " " + variable1); } inner(); } outer(); // logs Hello World // because (variable2 = "Hello") and (variable1 = "World") are the nearest // variables inside inner's scope.
20. Что такое замыкания?
↑ Это, наверное, самый сложный вопрос из всех этих вопросов, потому что Замыкания — спорная тема. Поэтому я объясню это из того, что я понимаю.
Замыкания – это просто способность функции во время объявления запоминать ссылки на переменные и параметры в ее текущей области, в области родительской функции, в области родительской функции до тех пор, пока она не достигнет глобальной область действия с помощью цепочки областей действия. По сути, это Scope, созданный при объявлении функции.
Примеры — отличный способ объяснить замыкания.
//Global's Scope var globalVar = "abc";
function a(){ //testClosures's Scope console.log(globalVar); }
a(); //logs "abc" /* Scope Chain Inside a function perspective
a's scope -> global's scope */
В этом примере, когда мы объявляем функцию a
, Global Scope является частью a's
замыкания.
Причина, по которой переменная globalVar
не имеет значения на изображении из-за того, что значение этой переменной может меняться в зависимости от где и когда мы вызываем a
function.
Но в нашем примере выше переменная globalVar
будет иметь значение abc.
Хорошо, давайте сложный пример.
var globalVar = "global"; var outerVar = "outer"
function outerFunc(outerParam) { function innerFunc(innerParam) { console.log(globalVar, outerParam, innerParam); } return innerFunc; }
const x = outerFunc(outerVar); outerVar = "outer-2"; globalVar = "guess" x("inner");
Это напечатает «угадай внешний внутренний». Объяснение этому заключается в том, что когда мы вызываем функцию outerFunc
и присваиваем возвращаемое значение функцией innerFunc
переменной x
, outerParam
будет иметь значение outer, даже если мы назначаем новое значение external-2 в переменную outerVar
, потому что
переназначение произошло после вызова функции outer
, и в то время, когда мы вызываем функцию outerFunc
, она ищет значение outerVar
в цепочке областей видимости , outerVar
будет иметь значение 'outer'. Теперь, когда мы вызываем переменную x
, которая имеет ссылку на innerFunc
,innerParam
будет иметь значение inner, потому что это значение, которое мы передаем при вызове, а переменная globalVar
будет иметь значение догадка, поскольку перед вызовом переменной x
мы присваиваем новое значение globalVar
, а во время вызова x
значение globalVar
в цепочке областей действия равно угадай.
У нас есть пример, демонстрирующий проблему неправильного понимания замыкания.
const arrFuncs = []; for(var i = 0; i < 5; i++){ arrFuncs.push(function (){ return i; }); } console.log(i); // i is 5
for (let i = 0; i < arrFuncs.length; i++) { console.log(arrFuncs[i]()); // all logs "5" }
Этот код работает не так, как мы ожидали, из-за замыканий.
Ключевое слово var
создает глобальную переменную, и когда мы нажимаем функцию,
мы возвращаем глобальную переменную i
. Поэтому, когда мы вызываем одну из этих функций в этом массиве после завершения цикла, она регистрирует 5
, поскольку мы получаем
текущее значение i
, равное 5
, и мы можем получить к нему доступ, поскольку это глобальная переменная. Потому что Closures сохраняет ссылки этой переменной, а не ее значения во время ее создания. Мы можем решить эту проблему, используя IIFES или изменив ключевое слово var
на let
для блочного охвата.
21. Что такое ложные значения в JavaScript?
const falsyValues = ['', 0, null, undefined, NaN, false];
Значения falsy — это значения, которые при преобразовании в логическое значение становятся falsy.
22. Как проверить, является ли значение ложным?
↑ Используйте логическую функцию или оператор двойного НЕ !!
23. Что делает "use strict"
?
↑ "use strict"
— это функция ES5 в JavaScript, которая переводит наш код в строгий режим в функциях или целых скриптах. . Строгий режим помогает нам избежать ошибок на ранних стадиях нашего кода и добавляет к нему ограничения.
Ограничения, которые накладывает Строгий режим.
- Назначение или доступ к переменной, которая не объявлена.
function returnY(){
"use strict";
y = 123;
return y;
}
- Присвоение значения доступной только для чтения или недоступной для записи глобальной переменной;
"use strict";
var NaN = NaN;
var undefined = undefined;
var Infinity = "and beyond";
- Удаление неудаляемого свойства.
"use strict"; const obj = {};
Object.defineProperty(obj, 'x', { value : '1' });
delete obj.x;
- Повторяющиеся имена параметров.
"use strict";
function someFunc(a, b, b, c){
}
- Создание переменных с использованием функции eval.
"use strict";
eval("var x = 1;");
console.log(x); //Throws a Reference Error x is not defined
- Значение по умолчанию this будет
undefined
.
"use strict";
function showMeThis(){ return this; }
showMeThis(); //returns undefined
В строгом режиме есть гораздо больше ограничений, чем эти.
24. Каково значение this
в JavaScript?
↑ По сути, this
относится к значению объекта, который в данный момент выполняет или вызывает функцию. Я говорю в настоящее время по той причине, что значение this меняется в зависимости от контекста, в котором мы его используем, и где мы его используем.
const carDetails = { name: "Ford Mustang", yearBought: 2005, getName(){ return this.name; }, isRegistered: true };
console.log(carDetails.getName()); // logs Ford Mustang
Это то, что мы обычно ожидаем, потому что в методе getName мы возвращаем this.name
, this
в этом контексте относится к объекту, который является объектом carDetails
, который в настоящее время является объектом-"владельцем" выполняемой функции.
Хорошо, давайте добавим немного кода, чтобы сделать его странным. Под оператором console.log
добавьте эти три строки кода
var name = "Ford Ranger"; var getCarName = carDetails.getName;
console.log(getCarName()); // logs Ford Ranger
Второй оператор console.log
печатает слово Ford Ranger, что странно, потому что в нашем первом операторе console.log
было напечатано Ford Mustang. Причина этого в том, что метод getCarName
имеет другой объект "владелец", которым является объект window
. Объявление переменных с ключевым словом var
в глобальной области видимости прикрепляет свойства в объекте window
с теми же именами, что и переменные. Помните, что this
в глобальной области видимости относится к объекту window
, когда "use strict"
не используется.
console.log(getCarName === window.getCarName); //logs true
console.log(getCarName === this.getCarName); // logs true
this
и window
в этом примере относятся к одному и тому же объекту.
Один из способов решения этой проблемы — использование методов apply
и call
в функциях.
console.log(getCarName.apply(carDetails)); //logs Ford Mustang
console.log(getCarName.call(carDetails)); //logs Ford Mustang
Методы apply
и call
предполагают, что первым параметром будет объект, который будет иметь значение this
внутри этой функции.
IIFE или выражение немедленно вызываемой функции, функции, объявленные в глобальной области видимости, анонимные функции и внутренние функции в методах внутри объекта имеют значение по умолчанию. элемента this, который указывает на объект window.
(function (){ console.log(this); })(); //logs the "window" object
function iHateThis(){ console.log(this); }
iHateThis(); //logs the "window" object
const myFavoriteObj = { guessThis(){ function getThis(){ console.log(this); } getThis(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } };
myFavoriteObj.guessThis(); //logs the "window" object myFavoriteObj.thisIsAnnoying(function (){ console.log(this); //logs the "window" object });
Если мы хотим получить значение свойства name
, которое является Marko Polo в объекте myFavoriteObj
, есть два способа решить эту проблему.
Сначала мы сохраняем значение this
в переменной.
const myFavoriteObj = {
guessThis(){
const self = this; //saves the this value to the "self" variable
function getName(){
console.log(self.name);
}
getName();
},
name: 'Marko Polo',
thisIsAnnoying(callback){
callback();
}
};
В этом изображении мы сохраняем значение this
, которое будет объектом myFavoriteObj
. Таким образом, мы можем получить к нему доступ внутри внутренней функции getName
.
Во-вторых, мы используем ES6 Стрелочные функции.
const myFavoriteObj = {
guessThis(){
const getName = () => {
//copies the value of "this" outside of this arrow function
console.log(this.name);
}
getName();
},
name: 'Marko Polo',
thisIsAnnoying(callback){
callback();
}
};
Стрелочные функции не имеют своего this
. Он копирует значение this
объемлющей лексической области или, в этом примере, значение this
вне внутренней функции getName
, которая будет объектом myFavoriteObj
. Мы также можем определить значение this
по тому, как вызывается функция.
25. Что такое prototype
объекта?
↑ Проще говоря, prototype
— это чертеж объекта. Он используется в качестве запасного варианта для свойств и методов, если он существует в текущем объекте. Это способ совместного использования свойств и функций между объектами. Это основная концепция прототипного наследования в JavaScript.
const o = {};
console.log(o.toString()); // logs [object Object]
Несмотря на то, что метод o.toString
не существует в объекте o
, он не выдает ошибку, а возвращает строку [object Object]
. Когда свойство не существует в объекте, оно ищет его прототип, а если оно все еще не существует, оно ищет прототип прототипа и так далее, пока не найдет свойство с то же самое в цепочке прототипов. Концом цепочки прототипов является Object.prototype.
console.log(o.toString === Object.prototype.toString); // logs true
// which means we we're looking up the Prototype Chain and it reached
// the Object.prototype and used the "toString" method.
26. Что такое IIFE, какая от него польза?
↑ IIFE или Выражение немедленно вызываемой функции — это функция, которая будет вызываться или выполняться после ее создания или объявления. Синтаксис для создания IIFE заключается в том, что мы заключаем function (){}
в круглые скобки ()
или оператор группировки для обработки функции как выражения, а после этого мы вызываем ее с другими круглыми скобками ()
. Итак, IIFE выглядит так (function(){})()
.
(function () {
}());
(function () {
})();
(function named(params) {
})();
(() => {
})();
(function (global) {
})(window);
const utility = (function () { return { //utilities }; })();
Все эти примеры действительны для IIFE. Второй пример показывает, что мы можем передавать аргументы в функцию IIFE. Последний пример показывает, что мы можем сохранить результат IIFE в переменную, чтобы мы могли ссылаться на него позже.
Наилучшее использование IIFE — создание функций настройки инициализации и избежание конфликтов имен с другими переменными в глобальной области видимости или загрязнения глобального пространства имен. Давайте рассмотрим пример.
<script src="https://cdnurl.com/somelibrary.js"></script>
Предположим, у нас есть ссылка на библиотеку somelibrary.js
, которая предоставляет некоторые глобальные функции, которые мы можем использовать в нашем коде, но в этой библиотеке есть два метода, которые мы не используем, createGraph
и drawGraph
, потому что в этих методах есть ошибки. И мы хотим реализовать собственные методы createGraph
и drawGraph
.
- Один из способов решить эту проблему — изменить структуру наших скриптов.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
function createGraph() {
// createGraph logic here
}
function drawGraph() {
// drawGraph logic here
}
</script>
Когда мы используем это решение, мы переопределяем те два метода, которые дает нам библиотека.
- Другой способ решить эту проблему — изменить имя наших собственных вспомогательных функций.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
function myCreateGraph() {
// createGraph logic here
}
function myDrawGraph() {
// drawGraph logic here
}
</script>
Когда мы используем это решение, мы также изменим эти вызовы функций на новые имена функций.
- Другой способ — использовать IIFE.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
const graphUtility = (function () {
function createGraph() {
// createGraph logic here
}
function drawGraph() {
// drawGraph logic here
}
return {
createGraph,
drawGraph
}
})();
</script>
В этом решении мы создаем служебную переменную, являющуюся результатом IIFE, которая возвращает объект, содержащий два метода createGraph
и drawGraph
.
Еще одна проблема, которую решает IIFE, представлена в этом примере.
var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
li[i].addEventListener('click', function (e) {
console.log(i);
})
}
Предположим, у нас есть элемент ul
с классом list-group и у него есть 5 дочерних элементов li
. И мы хотим console.log
значение i
, когда мы щелкаем отдельный элемент li
.
Но поведение, которое мы хотим в этом коде, не работает. Вместо этого он регистрирует 5
при каждом нажатии элемента li
. Наша проблема связана с тем, как работают замыкания. Замыкания — это просто способность функций запоминать ссылки на переменные в своей текущей области, в области родительской функции и в глобальной области. Когда мы объявляем переменные с помощью ключевого слова var
в глобальной области видимости, очевидно, мы создаем глобальную переменную i
. Поэтому, когда мы щелкаем элемент li
, он регистрирует 5, потому что это значение i
, когда мы ссылаемся на него позже в функции обратного вызова.
- Одним из решений этой проблемы является IIFE.
var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
(function (currentIndex) {
li[currentIndex].addEventListener('click', function (e) {
console.log(currentIndex);
})
})(i);
}
Это решение работает по той причине, что IIFE создает новую область для каждой итерации, и мы фиксируем значение i
и передаем его в параметр currentIndex
, поэтому значение currentIndex
отличается для каждой итерации, когда мы вызвать IIFE.
27. Что такое метод использования Function.prototype.apply
?
↑ apply
вызывает функцию, определяющую this
или объект владельца этой функции в момент вызова.
const details = { message: 'Hello World!' };
function getMessage(){ return this.message; }
getMessage.apply(details); // returns 'Hello World!'
Этот метод работает как Function.prototype.call
с той лишь разницей, как мы передаем аргументы. В apply
мы передаем аргументы в виде массива.
const person = { name: "Marko Polo" };
function greeting(greetingMessage) { return `${greetingMessage} ${this.name}`; }
greeting.apply(person, ['Hello']); // returns "Hello Marko Polo!"
28. Что такое метод использования Function.prototype.call
?
↑ call
вызывает функцию, определяющую this
или объект владельца этой функции в момент вызова.
const details = { message: 'Hello World!' };
function getMessage(){ return this.message; }
getMessage.call(details); // returns 'Hello World!'
Этот метод работает как Function.prototype.apply
с той лишь разницей, как мы передаем аргументы. В call
мы передаем непосредственно аргументы, разделяя их запятой ,
для каждого аргумента.
const person = { name: "Marko Polo" };
function greeting(greetingMessage) { return `${greetingMessage} ${this.name}`; }
greeting.call(person, 'Hello'); // returns "Hello Marko Polo!"
29. В чем разница между Function.prototype.apply
и Function.prototype.call
?
↑ Единственная разница между apply
и call
заключается в том, как мы передаем аргументы в вызываемую функцию. В apply
мы передаем аргументы в виде массива, а в call
мы передаем аргументы непосредственно в списке аргументов.
const obj1 = { result:0 };
const obj2 = { result:0 };
function reduceAdd(){ let result = 0; for(let i = 0, len = arguments.length; i < len; i++){ result += arguments[i]; } this.result = result; }
reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // returns 15 reduceAdd.call(obj2, 1, 2, 3, 4, 5); // returns 15
30. Каково использование Function.prototype.bind
?
↑ Метод bind
возвращает новую функцию, которая привязана
к определенному значению this
или объекту владелец, поэтому мы можем использовать его позже в нашем коде. Методы call
, apply
вызывают функцию немедленно, а не возвращают новую функцию, как метод bind
.
import React from 'react';
class MyComponent extends React.Component { constructor(props){ super(props); this.state = { value : "" } this.handleChange = this.handleChange.bind(this); // Binds the "handleChange" method to the "MyComponent" component }
handleChange(e){ //do something amazing here }
render(){ return ( <> <input type={this.props.type} value={this.state.value} onChange={this.handleChange} /> </> ) } }
31. Что такое функциональное программирование и какие особенности JavaScript делают его кандидатом в качестве функционального языка?
↑ Функциональное программирование — это декларативное парадигма программирования или шаблон того, как мы создаем наши приложения с помощью функций с использованием выражений. который вычисляет значение без изменения или изменения переданных ему аргументов.
JavaScript Array имеет методы map, filter, reduce, которые являются самыми известными функциями в мире функционального программирования из-за их полезности, а также потому, что они не мутируют и не изменяют массив, что делает эти функции чистыми, а JavaScript поддерживает замыкания и функции высшего порядка, которые являются характеристика функционального языка программирования.
- Метод map создает новый массив с результатами вызова предоставленной функции обратного вызова для каждого элемента массива.
const words = ["Functional", "Procedural", "Object-Oriented"];
const wordsLength = words.map(word => word.length);
- Метод filter создает новый массив со всеми элементами, прошедшими проверку в функции обратного вызова.
const data = [ { name: 'Mark', isRegistered: true }, { name: 'Mary', isRegistered: false }, { name: 'Mae', isRegistered: true } ];
const registeredUsers = data.filter(user => user.isRegistered);
- Метод reduce применяет функцию к аккумулятору и каждому элементу массива (слева направо), чтобы уменьшить его до одного значения.
const strs = ["I", " ", "am", " ", "Iron", " ", "Man"];
const result = strs.reduce((acc, currentStr) => acc + currentStr, "");
32. Что такое функции высшего порядка?
↑ Функции высшего порядка — это функции, которые могут возвращать функцию или получать аргумент или аргументы, имеющие значение функции.
function higherOrderFunction(param,callback){
return callback(param);
}
33. Почему функции называются объектами первого класса?
↑Функции в JavaScript являются объектами первого класса, поскольку они рассматриваются как любое другое значение в языке. Они могут быть назначены переменным, они могут быть свойствами объекта, называемыми методами, они могут быть элементом массива их можно передавать как аргументы функции и возвращать как значения функции. Единственная разница между функцией и любым другим значением в JavaScript заключается в том, что функции могут вызываться или вызываться.
34. Реализуйте метод Array.prototype.map
вручную.
function map(arr, mapCallback) {
// First, we check if the parameters passed are right.
if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') {
return [];
} else {
let result = [];
// We're making a results array every time we call this function
// because we don't want to mutate the original array.
for (let i = 0, len = arr.length; i < len; i++) {
result.push(mapCallback(arr[i], i, arr));
// push the result of the mapCallback in the 'result' array
}
return result; // return the result array
}
}
Как описание MDN метода Array.prototype.map
.
Метод map() создает новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.
35. Реализуйте метод Array.prototype.filter
вручную.
function filter(arr, filterCallback) {
// First, we check if the parameters passed are right.
if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function')
{
return [];
} else {
let result = [];
// We're making a results array every time we call this function
// because we don't want to mutate the original array.
for (let i = 0, len = arr.length; i < len; i++) {
// check if the return value of the filterCallback is true or "truthy"
if (filterCallback(arr[i], i, arr)) {
// push the current item in the 'result' array if the condition is true
result.push(arr[i]);
}
}
return result; // return the result array
}
}
Как описание MDN метода Array.prototype.filter
.
Метод filter() создает новый массив со всеми элементами, прошедшими проверку, реализованную предоставленной функцией.
36. Реализуйте метод Array.prototype.reduce
вручную.
function reduce(arr, reduceCallback, initialValue) { // First, we check if the parameters passed are right. if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== 'function') { return []; } else { // If no initialValue has been passed to the function we're gonna use the let hasInitialValue = initialValue !== undefined; let value = hasInitialValue ? initialValue : arr[0]; // first array item as the initialValue
// Then we're gonna start looping at index 1 if there is no // initialValue has been passed to the function else we start at 0 if // there is an initialValue. for (let i = hasInitialValue ? 0 : 1, len = arr.length; i < len; i++) { // Then for every iteration we assign the result of the // reduceCallback to the variable value. value = reduceCallback(value, arr[i], i, arr); } return value; } }
В качестве описания MDN метода Array.prototype.reduce
.
Метод reduce() выполняет функцию редуктора (которую вы предоставляете) для каждого элемента массива, в результате чего получается одно выходное значение.
37. Что такое объект arguments?
↑ Объект arguments представляет собой набор значений параметров, передаваемых в функцию. Это подобный массиву объект, поскольку он имеет свойство length, и мы можем получить доступ к отдельным значениям, используя нотацию индексации массива arguments[1]
, но у него нет встроенных методов в массиве. forEach
,reduce
, filter
и map
.
Это помогает нам узнать количество аргументов, передаваемых в функцию.
Мы можем преобразовать объект arguments
в массив, используя метод Array.prototype.slice
.
function one() {
return Array.prototype.slice.call(arguments);
}
Примечание: объект arguments
не работает со стрелочными функциями ES6.
function one() { return arguments; } const two = function () { return arguments; } const three = function three() { return arguments; }
const four = () => arguments;
four(); // Throws an error - arguments is not defined
Когда мы вызываем функцию four
, она выдает ошибку ReferenceError: arguments is not defined
. Мы можем решить эту проблему, если ваша среда поддерживает остальный синтаксис.
const four = (...args) => args;
Это автоматически помещает все значения параметров в массив.
38. Как создать объект без прототипа?
↑ Мы можем создать объект без прототипа, используя метод Object.create
.
const o1 = {}; console.log(o1.toString()); // logs [object Object] get this method to the Object.prototype
const o2 = Object.create(null); // the first parameter is the prototype of the object "o2" which in this // case will be null specifying we don't want any prototype console.log(o2.toString()); // throws an error o2.toString is not a function
39. Почему b
в этом коде становится глобальной переменной при вызове этой функции?
function myFunc() { let a = b = 0; }
myFunc();
Причина этого в том, что оператор присваивания или = имеет ассоциативность справа налево или оценку. Это означает, что когда в одном выражении появляется несколько операторов присваивания, они оцениваются справа налево. Итак, наш код становится таким.
function myFunc() { let a = (b = 0); }
myFunc();
Во-первых, вычислено выражение b = 0
, а в этом примере b
не объявлено. Таким образом, JS Engine создает глобальную переменную b
вне этой функции, после чего возвращаемое значение выражения b = 0
будет равно 0, и оно присваивается новой локальной переменной a
с ключевым словом let
.
Мы можем решить эту проблему, сначала объявив переменные, прежде чем присваивать им значение.
function myFunc() {
let a,b;
a = b = 0;
}
myFunc();
40. Что такое ECMAScript?
↑ ECMAScript — это стандарт для создания языков сценариев, что означает, что JavaScript следует изменениям спецификации в стандарте ECMAScript, поскольку он схема JavaScript.
41. Какие новые функции появились в ES6 или ECMAScript 2015?
- Стрелочные функции
- Занятия
- Шаблон строк
- Расширенные литералы объектов
- Деструктуризация объекта
- Обещания
- Генераторы
- Модули
- Символ
- Прокси
- Наборы
- Параметры функции по умолчанию
- Отдохни и расправься
- Область блока с помощью
let
иconst
42. В чем разница между ключевыми словами var
, let
и const
?
↑ Переменные, объявленные с помощью ключевого слова var
, являются областью действия функции.
Это означает, что доступ к переменным можно получить через эту функцию, даже если мы объявим эту переменную внутри блока.
function giveMeX(showX) { if (showX) { var x = 5; } return x; }
console.log(giveMeX(false)); console.log(giveMeX(true));
Первый оператор console.log
регистрирует undefined
, а второй 5
. Мы можем получить доступ к переменной x
из-за
того, что она поднята вверху области действия функции. Таким образом, наш код функции интерпретируется следующим образом.
function giveMeX(showX) {
var x; // has a default value of undefined
if (showX) {
x = 5;
}
return x;
}
Если вам интересно, почему он записывает undefined
в первый оператор console.log
, помните, что переменные, объявленные без начального значения, имеют значение по умолчанию undefined
.
Переменные, объявленные с помощью ключевых слов let
и const
, имеют блочную область действия. Что это означает, что доступ к переменной возможен только в том блоке {}
, где мы ее объявляем.
function giveMeX(showX) { if (showX) { let x = 5; } return x; }
function giveMeY(showY) { if (showY) { let y = 5; } return y; }
Если мы вызовем эту функцию с аргументом false
, она выдаст Reference Error
, потому что мы не можем получить доступ к переменным x
и y
вне этого блока, и эти переменные не подняты.
Существует также разница между let
и const
: мы можем назначать новые значения, используя let
, но не можем в const
, но const
имеют изменяемое значение. Это означает, что если значение, которое мы присваиваем const
, является объектом, мы можем изменить значения этих свойств, но не можем переназначить новое значение этой переменной.
43. Что такое стрелочные функции?
↑ Стрелочные функции — это новый способ создания функций в JavaScript. Функции со стрелками требуют немного времени для создания функций и имеют более чистый синтаксис, чем функциональное выражение, поскольку при их создании мы опускаем ключевое слово function
.
//ES5 Version var getCurrentDate = function (){ return new Date(); }
//ES6 Version const getCurrentDate = () => new Date();
В этом примере в версии ES5 есть объявление function(){}
и ключевое слово return
, необходимые для создания функции и возврата значения соответственно. В версии Стрелочная функция нам нужны только круглые скобки ()
, и нам не нужен оператор return
, потому что стрелочные функции имеют неявный возврат, если у нас есть только одно выражение или значение для возвращаться.
//ES5 Version function greet(name) { return 'Hello ' + name + '!'; }
//ES6 Version const greet = (name) => `Hello ${name}`; const greet2 = name => `Hello ${name}`;
Мы также можем использовать параметры в функциях со стрелками так же, как и в выражениях функций и объявлениях функций. Если у нас есть один параметр в Стрелочной функции, мы можем опустить круглые скобки, это также допустимо.
const getArgs = () => arguments
const getArgs2 = (...rest) => rest
Функции со стрелками не имеют доступа к объекту arguments
. Таким образом, вызов первой функции getArgs
вызовет ошибку. Вместо этого мы можем использовать остальные параметры, чтобы получить все аргументы, переданные в стрелочную функцию.
const data = {
result: 0,
nums: [1, 2, 3, 4, 5],
computeResult() {
// "this" here refers to the "data" object
const addAll = () => {
// arrow functions "copies" the "this" value of
// the lexical enclosing function
return this.nums.reduce((total, cur) => total + cur, 0)
};
this.result = addAll();
}
};
Функции со стрелками не имеют собственного значения this
. Он захватывает или получает значение this
лексически объемлющей функции, или в этом примере функция addAll
копирует значение this
метода computeResult
, и если мы объявим стрелочную функцию в глобальной области видимости, значением this
будет объект window
.
44. Что такое классы?
↑ Классы — это новый способ написания функций-конструкторов в JavaScript. Это синтаксический сахар для использования функций-конструкторов, он по-прежнему использует прототипы и наследование на основе прототипов под капотом.
//ES5 Version function Person(firstName, lastName, age, address){ this.firstName = firstName; this.lastName = lastName; this.age = age; this.address = address; }
Person.self = function(){ return this; }
Person.prototype.toString = function(){ return "[object Person]"; }
Person.prototype.getFullName = function (){ return this.firstName + " " + this.lastName; }
//ES6 Version class Person { constructor(firstName, lastName, age, address){ this.lastName = lastName; this.firstName = firstName; this.age = age; this.address = address; }
static self() { return this; }
toString(){ return "[object Person]"; }
getFullName(){ return `${this.firstName} ${this.lastName}`; } }
Переопределение методов и Наследование от другого класса.
//ES5 Version Employee.prototype = Object.create(Person.prototype);
function Employee(firstName, lastName, age, address, jobTitle, yearStarted) { Person.call(this, firstName, lastName, age, address); this.jobTitle = jobTitle; this.yearStarted = yearStarted; }
Employee.prototype.describe = function () { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; }
Employee.prototype.toString = function () { return "[object Employee]"; }
//ES6 Version class Employee extends Person { //Inherits from "Person" class constructor(firstName, lastName, age, address, jobTitle, yearStarted) { super(firstName, lastName, age, address); this.jobTitle = jobTitle; this.yearStarted = yearStarted; }
describe() { return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`; }
toString() { // Overriding the "toString" method of "Person" return "[object Employee]"; } }
Итак, как мы узнаем, что он использует прототипы под капотом?
class Something {
}
function AnotherSomething(){
} const as = new AnotherSomething(); const s = new Something();
console.log(typeof Something); // logs "function" console.log(typeof AnotherSomething); // logs "function" console.log(as.toString()); // logs "[object Object]" console.log(as.toString()); // logs "[object Object]" console.log(as.toString === Object.prototype.toString); console.log(s.toString === Object.prototype.toString); // both logs return true indicating that we are still using // prototypes under the hoods because the Object.prototype is // the last part of the Prototype Chain and "Something" // and "AnotherSomething" both inherit from Object.prototype
45. Что такое шаблонные литералы?
↑ Литералы шаблонов — это новый способ создания строк в JavaScript. Мы можем сделать Template Literal, используя символ обратной кавычки или обратной кавычки.
//ES5 Version var greet = 'Hi I\'m Mark';
//ES6 Version let greet = `Hi I'm Mark`;
В версии ES5 нам нужно экранировать '
, используя \
, чтобы экранировать обычную функциональность этого символа, которая в данном случае должна завершить это строковое значение. В шаблонных литералах нам не нужно этого делать.
//ES5 Version var lastWords = '\n' + ' I \n' + ' Am \n' + 'Iron Man \n';
//ES6 Version let lastWords = ` I Am Iron Man `;
В версии ES5 нам нужно добавить этот \n
, чтобы в нашей строке появилась новая строка. В шаблонных литералах нам не нужно этого делать.
//ES5 Version function greet(name) { return 'Hello ' + name + '!'; }
//ES6 Version const greet = name => { return `Hello ${name} !`; }
В версии ES5, если нам нужно добавить выражение или значение в строку, нам нужно использовать +
или оператор конкатенации строк. В шаблонных литералах мы можем встроить выражение, используя ${expr}
, что делает его чище, чем версия ES5.
46. Что такое деструктуризация объекта?
↑ Деструктуризация объектов — это новый и более понятный способ получения или извлечения значений из объекта или массива.
Предположим, у нас есть объект, который выглядит так.
const employee = {
firstName: "Marko",
lastName: "Polo",
position: "Software Developer",
yearHired: 2017
};
Старый способ получения свойств объекта заключается в том, что мы создаем переменную с тем же именем, что и свойство объекта. Это проблематично, потому что мы создаем новую переменную для каждого свойства. Представьте, что у нас есть большой объект с большим количеством свойств, и методы, использующие этот способ извлечения свойств, будут раздражать.
var firstName = employee.firstName;
var lastName = employee.lastName;
var position = employee.position;
var yearHired = employee.yearHired;
Если мы используем деструктурирование объектов, это выглядит чище и занимает немного времени, чем старый способ. Синтаксис деструктуризации объекта заключается в том, что если мы получаем свойства объекта, мы используем {}
, а внутри него мы указываем свойства, которые хотим извлечь, и если мы получаем данные из массива, мы используем []
.
let { firstName, lastName, position, yearHired } = employee;
Если мы хотим изменить имя переменной, которую мы хотим извлечь, мы используем синтаксис propertyName:newName
. В этом примере значение переменной fName
будет содержать значение свойства firstName
, а переменная lName
будет содержать значение свойства lastName
.
let { firstName: fName, lastName: lName, position, yearHired } = employee;
У нас также могут быть значения по умолчанию при деструктуризации. В этом примере, если свойство firstName
содержит значение undefined
в объекте, то при деструктуризации переменная firstName
будет содержать значение по умолчанию "Mark"
.
let { firstName = "Mark", lastName: lName, position, yearHired } = employee;
47. Что такое ES6 Modules
?
↑ Модули позволяют нам разделить нашу кодовую базу на несколько файлов для удобства сопровождения, и это позволяет нам не помещать весь наш код в один большой файл (блин). До того, как в ES6 появилась поддержка модулей, существовали две популярные модульные системы, которые использовались для поддержки кода в JavaScript.
- CommonJS — Nodejs
- AMD (определение асинхронного модуля) — Браузеры
По сути, синтаксис для использования модулей прост: import
используется для получения функций из другого файла или нескольких функций или значений, а export
используется для представления функциональность из файла или несколько функций или значений.
Экспорт функциональных возможностей в файл или именованный экспорт
Использование ES5 (CommonJS)
// Using ES5 CommonJS - helpers.js exports.isNull = function (val) { return val === null; }
exports.isUndefined = function (val) { return val === undefined; }
exports.isNullOrUndefined = function (val) { return exports.isNull(val) || exports.isUndefined(val); }
Использование модулей ES6
// Using ES6 Modules - helpers.js export function isNull(val){ return val === null; }
export function isUndefined(val) { return val === undefined; }
export function isNullOrUndefined(val) { return isNull(val) || isUndefined(val); }
Импорт функциональных возможностей в другой файл
// Using ES5 (CommonJS) - index.js const helpers = require('./helpers.js'); // helpers is an object const isNull = helpers.isNull; const isUndefined = helpers.isUndefined; const isNullOrUndefined = helpers.isNullOrUndefined;
// or if your environment supports Destructuring const { isNull, isUndefined, isNullOrUndefined } = require('./helpers.js');
// ES6 Modules - index.js import * as helpers from './helpers.js'; // helpers is an object
// or
import { isNull, isUndefined, isNullOrUndefined as isValid } from './helpers.js';
// using "as" for renaming named exports
Экспорт одной функции в файл или экспорт по умолчанию
Использование ES5 (CommonJS)
// Using ES5 (CommonJS) - index.js class Helpers { static isNull(val) { return val === null; }
static isUndefined(val) { return val === undefined; }
static isNullOrUndefined(val) { return this.isNull(val) || this.isUndefined(val); } }
module.exports = Helpers;
Использование модулей ES6
// Using ES6 Modules - helpers.js class Helpers { static isNull(val) { return val === null; }
static isUndefined(val) { return val === undefined; }
static isNullOrUndefined(val) { return this.isNull(val) || this.isUndefined(val); } }
export default Helpers
Импорт одной функции из другого файла
Использование ES5 (CommonJS)
// Using ES5 (CommonJS) - index.js
const Helpers = require('./helpers.js');
console.log(Helpers.isNull(null));
Использование модулей ES6
import Helpers from '.helpers.js'
console.log(Helpers.isNull(null));
Это основы использования модулей ES6. Я не буду объяснять все о модулях, потому что это широкая тема, а мой пост теперь очень длинный.
48. Что такое объект Set
и как он работает?
↑ Объект Set — это функция ES6, которая позволяет хранить уникальные значения, примитивы или ссылки на объекты. Значение в наборе может встречаться только один раз. Он проверяет, существует ли значение в заданном объекте, используя алгоритм SameValueZero.
Мы можем создать экземпляр Set
, используя конструктор Set
, и при желании можем передать Iterable
в качестве начального значения.
const set1 = new Set();
const set2 = new Set(["a","b","c","d","d","e"]);
Мы можем добавить новое значение в экземпляр Set
, используя метод add
, и поскольку add
возвращает объект Set
, мы можем сцепить вызовы add
. Если значение уже существует в объекте Set
, оно не будет добавлено снова.
set2.add("f");
set2.add("g").add("h").add("i").add("j").add("k").add("k");
// the last "k" will not be added to the set object because it already exists
Мы можем удалить значение из экземпляра Set
с помощью метода delete
, этот метод возвращает boolean
, указывающий true
, если значение существует в объекте Set
, и false
, указывающий, что значение не существует.
set2.delete("k") // returns true because "k" exists in the set object
set2.delete("z") // returns false because "z" does not exists in the set object
Мы можем проверить, существует ли конкретное значение в экземпляре Set
, используя метод has
.
set2.has("a") // returns true because "a" exists in the set object
set2.has("z") // returns false because "z" does not exists in the set object
Мы можем получить длину экземпляра Set
, используя свойство size
.
set2.size // returns 10
Мы можем удалить или удалить все элементы экземпляра Set
, используя файл clear
.
set2.clear(); // clears the set data
Мы можем использовать объект Set
для удаления повторяющихся элементов в массиве.
const numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5];
const uniqueNums = [...new Set(numbers)]; // has a value of [1,2,3,4,5,6,7,8]
49. Что такое функция обратного вызова?
↑ Функция обратного вызова — это функция, которая будет вызвана позже.
const btnAdd = document.getElementById('btnAdd');
btnAdd.addEventListener('click', function clickCallback(e) { // do something useless });
В этом примере мы ждем click event
в элементе с идентификатором btnAdd, если это clicked
, выполняется функция clickCallback
. Функция Обратный вызов добавляет некоторую функциональность к некоторым данным или событию. Методы reduce
, filter
и map
в Array ожидают обратного вызова в качестве параметра. Хорошая аналогия для обратного звонка: вы звоните кому-то, и если они не отвечают, вы оставляете сообщение и ожидаете, что они перезвонят. Звонок кому-либо или оставление сообщения – это событие или данные, а обратный вызов – это действие, которое вы ожидаете позже. .
50. Что такое обещания?
↑ Промисы — это один из способов обработки асинхронных операций в JavaScript. Он представляет значение асинхронной операции. Обещания были сделаны для решения проблемы выполнения и работы с асинхронным кодом до обещаний, что мы используем обратные вызовы.
fs.readFile('somefile.txt', function (e, data) {
if (e) {
console.log(e);
}
console.log(data);
});
Проблема с этим подходом, если у нас есть еще одна асинхронная операция внутри обратного вызова и еще одна. У нас будет беспорядочный и нечитаемый код. Этот код называется Ад обратных вызовов.
//Callback Hell yucksss
fs.readFile('somefile.txt', function (e, data) {
//your code here
fs.readdir('directory', function (e, files) {
//your code here
fs.mkdir('directory', function (e) {
//your code here
})
})
})
Если мы будем использовать промисы в этом коде, он будет более читаемым, простым для понимания и простым в обслуживании.
promReadFile('file/path')
.then(data => {
return promReaddir('directory');
})
.then(data => {
return promMkdir('directory');
})
.catch(e => {
console.log(e);
})
Обещания имеют 3 разных состояния.
Ожидание — начальное состояние промиса. Результат обещания еще не известен, потому что операция еще не завершена.
Выполнено — асинхронная операция завершена и выполнена успешно с результирующим значением.
Отклонено — асинхронная операция завершилась неудачно, и есть причина, почему она не удалась.
Урегулировано — если обещание было выполнено или отклонено.
Конструктор Promise имеет два параметра, которые являются функциями resolve
и reject
соответственно.
Если асинхронная операция была завершена без ошибок, вызовите функцию resolve
для разрешения обещания или если произошла ошибка
вызвать функцию reject
и передать ей ошибку или причину.
Мы можем получить доступ к результату выполненного обещания с помощью метода .then
и отловить ошибки в методе .catch
. Мы объединяем несколько асинхронных операций обещания в методе .then
, потому что метод .then
возвращает Promise, как в примере на изображении выше.
const myPromiseAsync = (...args) => { return new Promise((resolve, reject) => { doSomeAsync(...args, (error, data) => { if (error) { reject(error); } else { resolve(data); } }) }) }
myPromiseAsync() .then(result => { console.log(result); }) .catch(reason => { console.log(reason); })
Мы можем создать вспомогательную функцию, которая преобразует асинхронную операцию с обратным вызовом в обещание. Она работает как служебная функция promisify из основного модуля узла util
.
const toPromise = (asyncFuncWithCallback) => { return (...args) => { return new Promise((res, rej) => { asyncFuncWithCallback(...args, (e, result) => { return e ? rej(e) : res(result); }); }); } }
const promReadFile = toPromise(fs.readFile);
promReadFile('file/path') .then((data) => { console.log(data); }) .catch(e => console.log(e));
51. Что такое async/await и как это работает?
↑ async/await — это новый способ написания асинхронного или неблокирующего кода в JavaScript. Он построен на основе Promises. Это делает написание асинхронного кода более читабельным и чистым, чем
Promises и Callbacks. Но вы должны изучить основы Promises, прежде чем использовать эту функцию, потому что, как я уже говорил ранее, она построена на основе Promises, что означает, что она по-прежнему использует Promises под капотом.
Использование обещаний.
function callApi() {
return fetch("url/to/api/endpoint")
.then(resp => resp.json())
.then(data => {
//do something with "data"
}).catch(err => {
//do something with "err"
});
}
Использование асинхронного/ожидания.
Примечание. Мы используем старый оператор try/catch для отлова любых ошибок, которые произошли в любой из этих асинхронных операций внутри оператор try.
async function callApi() {
try {
const resp = await fetch("url/to/api/endpoint");
const data = await resp.json();
//do something with "data"
} catch (e) {
//do something with "err"
}
}
Примечание. Ключевое слово async перед объявлением функции заставляет функцию неявно возвращать обещание.
const giveMeOne = async () => 1;
giveMeOne() .then((num) => { console.log(num); // logs 1 });
Примечание. Ключевое слово await можно использовать только внутри асинхронной функции. Использование ключевого слова await в любой другой функции, не являющейся асинхронной функцией, вызовет ошибку. Ключевое слово await ожидает возврата правого выражения (предположительно Promise) перед выполнением следующей строки кода.
const giveMeOne = async () => 1;
function getOne() { try { const num = await giveMeOne(); console.log(num); } catch (e) { console.log(e); } }
//Throws a Compile-Time Error = Uncaught SyntaxError: await is only valid in an async function
async function getTwo() { try { const num1 = await giveMeOne(); //finishes this async operation first before going to const num2 = await giveMeOne(); //this line return num1 + num2; } catch (e) { console.log(e); } }
await getTwo(); // returns 2
52. В чем разница между оператором Spread и оператором Rest?
↑ Оператор Spread и параметры Rest имеют один и тот же оператор ...
, разница между ними заключается в том, что оператор Spread мы задаем. strong> или распространить отдельные данные массива на другие данные, в то время как остальные параметры используются в функции или массиве для получения всех аргументов или значения и поместить их в массив или извлечь некоторые из них.
function add(a, b) { return a + b; };
const nums = [5, 6]; const sum = add(...nums); console.log(sum);
В этом примере мы используем оператор расширения, когда мы вызываем функцию add
, мы расширяем массив nums
. Таким образом, значение параметра a
будет 5, а значение b
будет равно 6. Таким образом, сумма будет 11.
function add(...rest) { return rest.reduce((total,current) => total + current); };
console.log(add(1, 2)); // logs 3 console.log(add(1, 2, 3, 4, 5)); // logs 15
В этом примере у нас есть функция add
, которая принимает любое количество аргументов, добавляет их все и возвращает итог.
const [first, ...others] = [1, 2, 3, 4, 5];
console.log(first); //logs 1
console.log(others); //logs [2,3,4,5]
В другом примере мы используем оператор Rest для извлечения всех оставшихся значений массива и помещения их в массив others
, кроме первого элемента.
53. Что такое параметры по умолчанию?
↑ Параметры по умолчанию — это новый способ определения переменных по умолчанию в JavaScript, он доступен в ES6 или ECMAScript 2015. Strong> Версия.
//ES5 Version function add(a,b){ a = a || 0; b = b || 0; return a + b; }
//ES6 Version function add(a = 0, b = 0){ return a + b; } //If we don't pass any argument for 'a' or 'b' then // it's gonna use the "default parameter" value which is 0 add(1); // returns 1
Мы также можем использовать Destructuring в параметрах по умолчанию.
function getFirst([first, ...rest] = [0, 1]) { return first; }
getFirst(); // returns 0 getFirst([10,20,30]); // returns 10
function getArr({ nums } = { nums: [1, 2, 3, 4] }){ return nums; }
getArr(); // returns [1, 2, 3, 4] getArr({nums:[5,4,3,2,1]}); // returns [5,4,3,2,1]
Мы также можем использовать параметры, определенные первыми, для параметров, определенных после них.
function doSomethingWithValue(value = "Hello World", callback = () => { console.log(value) }) {
callback();
}
doSomethingWithValue(); //logs "Hello World"
54. Что такое объекты-оболочки?
↑ Примитивные значения, такие как string
, number
и boolean
, за исключением null
и undefined
, имеют свойства и методы, даже если они не являются objects
.
let name = "marko";
console.log(typeof name); // logs "string" console.log(name.toUpperCase()); // logs "MARKO"
name
— это значение primitive string
, не имеющее свойств и методов, но в этом примере мы вызываем метод toUpperCase()
, который не выдает ошибку, а возвращает MARKO
.
Причина этого в том, что значение primitive
временно преобразуется или принуждается к object
, поэтому переменная name
ведет себя как object
. Все primitive
, кроме null
и undefined
, имеют объекты-оболочки. Объекты-оболочки: String
, Number
, Boolean
, Symbol
и BigInt
. В данном случае вызов name.toUpperCase()
за кадром выглядит так.
console.log(new String(name).toUpperCase()); // logs "MARKO"
Вновь созданный объект немедленно отбрасывается после того, как мы закончили доступ к свойству или вызов метода.
55. В чем разница между неявным и явным принуждением?
↑ Неявное приведение — это способ преобразования значений в другой тип без того, чтобы программист делал это напрямую или вручную.
Предположим, у нас есть пример ниже.
console.log(1 + '6');
console.log(false + true);
console.log(6 * '2');
Первая инструкция console.log
регистрирует 16
. В других языках это вызовет ошибку времени компиляции, но в JavaScript 1
преобразуется в string
, а затем объединяется с оператором +
. Мы ничего не делали, но он был автоматически конвертирован для нас с помощью JavaScript.
Второй оператор console.log
регистрирует 1
, он преобразует false
в boolean
, что приводит к 0
, а true
будет 1
, следовательно, результат 1
.
Третий оператор console.log
регистрирует 12
, он преобразует '2'
в number
перед умножением 6 * 2
, следовательно, результат 12
.
Правила приведения JavaScript
В то время как явное приведение — это способ преобразования значений в другой тип, когда мы (программисты) явно делаем это.
console.log(1 + parseInt('6'));
В этом примере мы используем функцию parseInt
для преобразования '6'
в number
, а затем добавляем 1
и 6
с помощью оператора +
.
56. Что такое NaN
? и Как проверить, является ли значение NaN
?
↑ NaN
означает, что 'Not A Number' — это значение в JavaScript, которое является результатом преобразования или выполнения операции с числом в нечисловое значение, следовательно, приводит к NaN
.
let a;
console.log(parseInt('abc')); console.log(parseInt(null)); console.log(parseInt(undefined)); console.log(parseInt(++a)); console.log(parseInt({} * 10)); console.log(parseInt('abc' - 2)); console.log(parseInt(0 / 0)); console.log(parseInt('10a' * 10));
JavaScript имеет встроенный метод isNaN
, который проверяет, является ли значение isNaN
значением. Но эта функция имеет странное поведение.
console.log(isNaN()); //logs true
console.log(isNaN(undefined)); //logs true
console.log(isNaN({})); //logs true
console.log(isNaN(String('a'))); //logs true
console.log(isNaN(() => { })); //logs true
Все эти операторы console.log
возвращают true
, несмотря на то, что переданные нами значения не являются NaN
.
В ES6 или ECMAScript 2015 рекомендуется использовать метод Number.isNaN
, потому что он действительно проверяет значение, если оно действительно равно NaN
, или мы можем создать собственную вспомогательную функцию, которая проверяет эта проблема, потому что в JavaScript NaN
— единственное значение, которое не равно самому себе.
function checkIfNaN(value) {
return value !== value;
}
57. Как проверить, является ли значение массивом?
↑ Мы можем проверить, является ли значение массивом, используя метод Array.isArray
, доступный из глобального объекта массив. Он возвращает true, если переданный ему параметр является массивом, в противном случае — false.
console.log(Array.isArray(5)); //logs false console.log(Array.isArray("")); //logs false console.log(Array.isArray()); //logs false console.log(Array.isArray(null)); //logs false console.log(Array.isArray({ length: 5 })); //logs false
console.log(Array.isArray([])); //logs true
Если ваша среда не поддерживает этот метод, вы можете использовать реализацию полифилла.
function isArray(value){
return Object.prototype.toString.call(value) === "[object Array]"
}
58. Как проверить, является ли число четным, не используя оператор %
или по модулю?
↑ Для этой задачи мы можем использовать оператор побитовое И&
. &
работает со своим операндом и обрабатывает их как двоичные значения и выполняет операцию И.
function isEven(num) {
if (num & 1) {
return false;
} else {
return true;
}
};
0
в двоичном формате равно 000.1
в двоичном формате равно 001.2
в двоичном формате равно 010.
> 3
в двоичном формате равно 011.4
в двоичном формате равно 100.5
в двоичном формате равно 101.
6
в двоичном формате равно 110.7
в двоичном формате равно 111.
и так далее...
a
b
a & b
0 0 0 0 1 0 1 0 0 1 1 1
Итак, когда мы console.log
это выражение 5 & 1
возвращает 1
. Хорошо, сначала оператор &
преобразует оба числа в двоичные, поэтому 5
превращается в 101, а 1
превращается в 001.
Затем он сравнивает каждый бит (0 и 1) с помощью побитового оператора И. 101 &
001. Как видно из таблицы, результат может быть только 1
, если a
И b
равно 1
.
101 & 001
101 001 001
- Итак, сначала мы сравниваем самый левый бит
1&0
, результат должен быть0
. - Затем сравниваем средний бит
0&0
результат должен быть0
. - Затем мы сравниваем последний бит
1&1
, результат должен быть1
. - Затем двоичный результат
001
будет преобразован в десятичное число, которое будет1
.
Если мы console.log
это выражение 4 & 1
вернет 0
. Зная, что последний бит 4
равен 0
, а 0 & 1
будет 0
. Если вам трудно это понять, мы можем использовать рекурсивную функцию для решения этой проблемы.
function isEven(num) {
if (num < 0 || num === 1) return false;
if (num == 0) return true;
return isEven(num - 2);
}
59. Как проверить, существует ли определенное свойство в объекте?
↑ Есть три возможных способа проверить, существует ли свойство в объекте.
Во-первых, с помощью оператора in
. Синтаксис использования оператора in
подобен этому propertyname in object
. Он возвращает true
, если свойство существует, в противном случае возвращает false
.
const o = { "prop" : "bwahahah", "prop2" : "hweasa" };
console.log("prop" in o); //This logs true indicating the property "prop" is in "o" object console.log("prop1" in o); //This logs false indicating the property "prop" is not in "o" object
Во-вторых, использование метода hasOwnProperty
в объектах. Этот метод доступен для всех объектов в JavaScript. Он возвращает true
, если свойство существует, в противном случае возвращает false
.
//Still using the o object in the first example.
console.log(o.hasOwnProperty("prop2")); // This logs true
console.log(o.hasOwnProperty("prop1")); // This logs false
В-третьих, используя обозначение в скобках obj["prop"]
. Если свойство существует, оно возвращает значение этого свойства, в противном случае будет возвращено undefined
.
//Still using the o object in the first example.
console.log(o["prop"]); // This logs "bwahahah"
console.log(o["prop1"]); // This logs undefined
60. Что такое АЯКС?
↑ AJAX означает Асинхронный JavaScript и XML. Это группа связанных технологий, используемых для асинхронного отображения данных. Это означает, что мы можем отправлять данные на сервер и получать данные с сервера без перезагрузки веб-страницы.
Технологии, используемые для AJAX.
- HTML — структура веб-страницы
- CSS — стиль веб-страницы.
- JavaScript — поведение веб-страницы и обновления DOM.
- XMLHttpRequest API — используется для отправки и получения данных с сервера.
- PHP,Python,Nodejs — некоторые серверные языки
61. Какие есть способы создания объектов в JavaScript?
↑ Использование Object Literal.
const o = { name: "Mark", greeting() { return `Hi, I'm ${this.name}`; } };
o.greeting(); //returns "Hi, I'm Mark"
Использование функций-конструкторов.
function Person(name) { this.name = name; }
Person.prototype.greeting = function () { return `Hi, I'm ${this.name}`; }
const mark = new Person("Mark");
mark.greeting(); //returns "Hi, I'm Mark"
Использование метода Object.create.
const n = { greeting() { return `Hi, I'm ${this.name}`; } };
const o = Object.create(n); // sets the prototype of "o" to be "n"
o.name = "Mark";
console.log(o.greeting()); // logs "Hi, I'm Mark"
62. В чем разница между методами Object.seal
и Object.freeze
?
↑ Разница между этими двумя методами заключается в том, что когда мы применяем метод Object.freeze
к объекту, свойства этого объекта неизменяемы, то есть мы не можем изменять или редактировать значения этих свойств. В то время как в методе Object.seal
мы можем изменить эти существующие свойства, но мы не можем добавить новые свойства к объекту.
63. В чем разница между оператором in
и методом hasOwnProperty
в объектах?
↑ Как вы знаете, обе эти функции проверяют, существует ли свойство в объекте. Он вернет true
false. Разница между ними заключается в том, что оператор in
также проверяет цепочку прототипов объектов, если свойство не было найдено в текущем объекте, в то время как метод hasOwnProperty
просто проверяет, существует ли свойство в текущем объекте, игнорируя цепочка прототипов.
// We'll still use the object in the previous question. console.log("prop" in o); // This logs true; console.log("toString" in o); // This logs true, the toString method is available in this object's prototype which is the Object.prototype
console.log(o.hasOwnProperty("prop")); // This logs true console.log(o.hasOwnProperty("toString")); // This logs false, does not check the object's prototype
64. Как можно работать с асинхронным кодом в JavaScript?
- Обратные звонки
- Обещания
- асинхронно/ожидание
- Библиотеки типа async.js, bluebird, q, co
65. В чем разница между выражением функции и объявлением функции?
↑ Допустим, у нас есть пример ниже.
hoistedFunc(); notHoistedFunc();
function hoistedFunc(){ console.log("I am hoisted"); }
var notHoistedFunc = function(){ console.log("I will not be hoisted!"); }
Вызов notHoistedFunc
вызывает ошибку, а вызов hoistedFunc
— нет, потому что hoistedFunc
поднят, а notHoistedFunc
— нет.
Читать Подъем здесь.
66. Сколько способов можно вызвать функцию?
↑ Существует 4 способа вызвать функцию в JavaScript. Вызов определяет значение this
или объект "владелец" этой функции.
- Вызов как функция. Если функция вызывается не как метод, конструктор или с методами
apply
,call
, она вызывается как функция. Объектом «владельца» этой функции будет объектwindow
.
//Global Scope
function add(a,b){ console.log(this); return a + b; }
add(1,5); // logs the "window" object and returns 6
const o = { method(callback){ callback(); } }
o.method(function (){ console.log(this); // logs the "window" object });
- Вызов как метод. Если свойство объекта имеет значение функции, мы называем его методом. Когда этот метод вызывается, значением
this
этого метода будет этот объект.
const details = { name : "Marko", getName(){ return this.name; } }
details.getName(); // returns Marko // the "this" value inside "getName" method will be the "details" object
- Вызов в качестве конструктора. Если функция была вызвана с ключевым словом
new
перед ней, то она называетсяfunction constructor
. Будет создан пустой объект, иthis
будет указывать на этот объект.
function Employee(name, position, yearHired) { // creates an empty object {} // then assigns the empty object to the "this" keyword // this = {}; this.name = name; this.position = position; this.yearHired = yearHired; // inherits from Employee.prototype // returns the "this" value implicitly if no // explicit return statement is specified };
const emp = new Employee("Marko Polo", "Software Developer", 2017);
- Вызов с помощью методов
apply
иcall
. Если мы хотим явно указать значениеthis
или объект-"владелец" функции, мы можем использовать эти методы. Эти методы доступны для всех функций.
const obj1 = { result:0 };
const obj2 = { result:0 };
function reduceAdd(){ let result = 0; for(let i = 0, len = arguments.length; i < len; i++){ result += arguments[i]; } this.result = result; }
reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); //the "this" object inside the "reduceAdd" function will be "obj1" reduceAdd.call(obj2, 1, 2, 3, 4, 5); //the "this" object inside the "reduceAdd" function will be "obj2"
67. Что такое мемоизация и зачем она нужна?
↑ запоминание — это процесс создания функции, способной запоминать свои ранее вычисленные результаты или значения.
Использование функции memoization заключается в том, что мы избегаем вычисления этой функции, если она уже выполнялась в последних вычислениях с теми же аргументами. Это экономит время, но имеет недостаток, заключающийся в том, что мы будем потреблять больше памяти для сохранения предыдущих результатов.
68. Реализуйте вспомогательную функцию запоминания.
function memoize(fn) { const cache = {}; return function (param) { if (cache[param]) { console.log('cached'); return cache[param]; } else { let result = fn(param); cache[param] = result; console.log(`not cached`); return result; } } }
const toUpper = (str ="")=> str.toUpperCase();
const toUpperMemoized = memoize(toUpper);
toUpperMemoized("abcdef"); toUpperMemoized("abcdef");
Эта вспомогательная функция memoize работает только с функцией, которая принимает один аргумент. Нам нужно создать вспомогательную функцию memoize, которая принимает несколько аргументов.
const slice = Array.prototype.slice; function memoize(fn) { const cache = {}; return (...args) => { const params = slice.call(args); console.log(params); if (cache[params]) { console.log('cached'); return cache[params]; } else { let result = fn(...args); cache[params] = result; console.log(`not cached`); return result; } } } const makeFullName = (fName, lName) => `${fName} ${lName}`; const reduceAdd = (numbers, startingValue = 0) => numbers.reduce((total, cur) => total + cur, startingValue);
const memoizedMakeFullName = memoize(makeFullName); const memoizedReduceAdd = memoize(reduceAdd);
memoizedMakeFullName("Marko", "Polo"); memoizedMakeFullName("Marko", "Polo");
memoizedReduceAdd([1, 2, 3, 4, 5], 5); memoizedReduceAdd([1, 2, 3, 4, 5], 5);
69. Почему typeof null
возвращает object
? Как проверить, является ли значение null
?
↑ typeof null == 'object'
всегда будет возвращать true
, потому что это была реализация null
с момента рождения JavaScript. Было предложено исправить изменение typeof null == 'object'
на typeof null == 'null'
, но оно было отклонено, так как это приведет к большему количеству ошибок.
Мы можем использовать оператор ===
или строгого равенства, чтобы проверить, является ли значение null
.
function isNull(value){
return value === null;
}
70. Что делает ключевое слово new
?
↑ Ключевое слово new
используется с функциями конструктора для создания объектов
в JavaScript.
Предположим, у нас есть пример кода ниже.
function Employee(name, position, yearHired) { this.name = name; this.position = position; this.yearHired = yearHired; };
const emp = new Employee("Marko Polo", "Software Developer", 2017);
Ключевое слово new
выполняет 4 функции.
- Создает пустой объект.
- Присваивает этому пустому объекту значение
this
. - Функция наследуется от functionName.prototype.
- Возвращает
this
, если не используется явный операторreturn
.
На изображении выше он сначала создаст пустой объект {}
, затем
присвоит этому пустому объекту this = {}
значение this
и добавит свойства этому объекту this
. Поскольку у нас нет явного оператора return
, он автоматически возвращает нам this
.