Перевод статьи Gustavo Azevedo The Definitive JavaScript Handbook for your next developer interview.
JavaScript был и продолжает быть самым популярным языком программирования, согласно опросу Stack Overflow Survey. Неудивительно, что 1/3 всех вакансий требуют знания JavaScript. Поэтому, если вы планируете работать разработчиком в ближайшем будущем, то вам следует ознакомиться с этим черезвычайно популярным языком.
Цель публикации — собрать в одном месте все концепции JavaScript, которые часто встречаются на собеседовании.
Существует 7 встроенных типов: null, undefined, boolean, number, string, object и symbol(ES6).
Все эти типы называются примитивами(все, кроме object).
Undefined — это отсутствие объявления переменной. Он используется как значение по умолчанию для не инициализированных переменных, аргументов функций(в которые не были переданы значения) и пропущенных значений у объектов.
Null — это отсутствие значения переменной.
Посмотрите на этот пример:
Здесь, значение переменной name вернет true, поэтому консоль выведет: «Joey doesn’t share food!». Но откуда нам знать что вернет true, а что вернет false?
Ложные значения — это значения, которые вернут нам false при их касте к типу Boolean.
К ложным значениям относятся: "", 0, null, undefined, NaN и false.
Все что не является ложным — вернет true.
Да. Вы все прочитали верно. Пустые массивы, объекты и функции возвращают true!
Первая вещь, о которой вам нужно знать — это оператор +. Это сложный оператор, потому что он работает для сложения чисел и конкатенации строк.
Операторы *, / и - — это эксклюзивные операторы для числовых операций. Поэтому, когда они используются со строкой, это заставляет ее преобразовываться к числовому формату.
Широко распространенное мнение о том, что == проверяет равенство, а === проверяет на равенство и тип. Но это неправильно представление.
По факту, == проверяет равенство вместе с преобразованием, а === проверяет равенство двух значений без него — строгое сравнение.
Преобразование может быть сложным. Обратите внимание на пример ниже:
Что вы ожидаете от следующего сравнения?
Он вернет true. Почему?
Что действительно происходит под капотом, так это то, что если вы сравниваете логическое значение с чем-то иным, кроме логического значения, тогда JavaScript преобразует boolean к типу number и только тогда производит сравнение(2).
Теперь наше выражение заключается в сравнении number и string. Для этого JavaScript заставит строку преобразоваться в тип number(3).
Поэтому в результате мы получаем выражение 0 == 0, которое равно true.
Для полго понимания того, как подобные сравнения производятся, вы можете проверить документацию ES5 здесь.
Еще вы можете глянуть на чит-лист.
Вот вам парочку сложных примеров:
Null, undefined, boolean, number, string и ES6 symbol — это простые значения(также известные как примитивы). Они всегда копируют свое содержание в переменную.
Сложные значения всегда создают копию ссылки при присваивании.
Чтобы скопировать сложное значение, вам нужно сделать его копию, тогда ссылка не будет указывать на его исходное расположение.
Область видимости задает контекст выполнения. Она определяет доступность значения и функций в коде.
Глобальная область видимости — это самая объемная область. Значения, объявленные вне функций, являются глобальными и могут быть доступны в любой части программы. В браузере объект window является хранилищем глобальной области видимости.
Локальная область видимости — это область заключенная в функцию. Переменные объявленные в локальной области видимости, могут быть доступны только внутри нее.
Вы можете думать об областях видимости, как о серии дверей, уменьшающихся по размеру(от самых больших до самых маленьких). Короткий человек, который вписывается в самую маленькую дверь — самую внутреннюю область — также пройдет через любые большие двери — внешние области.
Но, например, высокий человек, который застрял в третьей двери, будет иметь доступ ко всем предыдущим дверям — внешним областям, но не к каким-либо меньшим по размеру дверям — внутренним областям.
Поведение «движущихся» объявлений переменных и функций в верхнюю часть их соответствующих областей на этапе компиляции — называется поднятием.
Объявление функции полностью подняты. Это означает, что объявленная функция может быть вызвана до ее определения.
Переменные частично подняты. Переменные, объявленные с помощью оператора var подняты, но их значения — нет.
let и const не поддерживают подъемы.
Функциональное выражение создается, когда исполнение достигает его объявления(оно не является поднятым).
Функциональное объявление может быть вызвано до и после его описания(оно является поднятым).
До введения стандарта ES6 переменную можно было объявить только с помощью var. Переменные и функции, объявленные внутри другой функции, не могут быть доступны ни одной из охватывающих областей — они ограничены функциональностью.
Значения объявленные внутри фигурных скобок могут быть использованы и за их пределами.
Примечание. Переменная объявленная без ключевого слова var, let или const создает переменную var в глобальной области.
ES6 let и const являются новыми. Они не подъемные + пара фигурных скобок, в которых они объявлены, ограничивают их область видимости.
Распространенным заблуждением является то, что const является неизменяемым. Он не может быть переобъявлен, но его значение(если это array/object), на которое он ссылается, может быть изменено!
JavaScript был и продолжает быть самым популярным языком программирования, согласно опросу Stack Overflow Survey. Неудивительно, что 1/3 всех вакансий требуют знания JavaScript. Поэтому, если вы планируете работать разработчиком в ближайшем будущем, то вам следует ознакомиться с этим черезвычайно популярным языком.
Цель публикации — собрать в одном месте все концепции JavaScript, которые часто встречаются на собеседовании.
Типы и Преобразования
Существует 7 встроенных типов: null, undefined, boolean, number, string, object и symbol(ES6).
Все эти типы называются примитивами(все, кроме object).
typeof 0 // number
typeof true // boolean
typeof 'Hello' // string
typeof Math // object
typeof null // object !!
typeof Symbol('Hi') // symbol (New ES6)
Null vs Undefined
Undefined — это отсутствие объявления переменной. Он используется как значение по умолчанию для не инициализированных переменных, аргументов функций(в которые не были переданы значения) и пропущенных значений у объектов.
Null — это отсутствие значения переменной.
Неявное преобразование
Посмотрите на этот пример:
var name = 'Joey';
if (name) {
console.log(name + " doesn't share food!") // Joey doesn’t share food!
}
Здесь, значение переменной name вернет true, поэтому консоль выведет: «Joey doesn’t share food!». Но откуда нам знать что вернет true, а что вернет false?
Ложные значения — это значения, которые вернут нам false при их касте к типу Boolean.
К ложным значениям относятся: "", 0, null, undefined, NaN и false.
Все что не является ложным — вернет true.
Boolean(null) // false
Boolean('hello') // true
Boolean('0') // true
Boolean(' ') // true
Boolean([]) // true
Boolean(function(){}) // true
Да. Вы все прочитали верно. Пустые массивы, объекты и функции возвращают true!
Строки и Числовые преобразования
Первая вещь, о которой вам нужно знать — это оператор +. Это сложный оператор, потому что он работает для сложения чисел и конкатенации строк.
Операторы *, / и - — это эксклюзивные операторы для числовых операций. Поэтому, когда они используются со строкой, это заставляет ее преобразовываться к числовому формату.
1 + "2" = "12"
"" + 1 + 0 = "10"
"" - 1 + 0 = -1
"-9\n" + 5 = "-9\n5"
"-9\n" - 5 = -14
"2" * "3" = 6
4 + 5 + "px" = "9px"
"$" + 4 + 5 = "$45"
"4" - 2 = 2
"4px" - 2 = NaN
null + 1 = 1
undefined + 1 = NaN
== vs ===
Широко распространенное мнение о том, что == проверяет равенство, а === проверяет на равенство и тип. Но это неправильно представление.
По факту, == проверяет равенство вместе с преобразованием, а === проверяет равенство двух значений без него — строгое сравнение.
2 == '2' // True
2 === '2' // False
undefined == null // True
undefined === null // False
Преобразование может быть сложным. Обратите внимание на пример ниже:
let a = '0';
console.log(Boolean(a)); // True
let b = false;
console.log(Boolean(b)); // False
Что вы ожидаете от следующего сравнения?
console.log(a == b); (1)
Он вернет true. Почему?
Что действительно происходит под капотом, так это то, что если вы сравниваете логическое значение с чем-то иным, кроме логического значения, тогда JavaScript преобразует boolean к типу number и только тогда производит сравнение(2).
Теперь наше выражение заключается в сравнении number и string. Для этого JavaScript заставит строку преобразоваться в тип number(3).
Поэтому в результате мы получаем выражение 0 == 0, которое равно true.
'0' == false (1)
'0' == 0 (2)
0 == 0 (3)
Для полго понимания того, как подобные сравнения производятся, вы можете проверить документацию ES5 здесь.
Еще вы можете глянуть на чит-лист.
Вот вам парочку сложных примеров:
false == "" // true
false == [] // true
false == {} // false
"" == 0 // true
"" == [] // true
"" == {} // false
0 == [] // true
0 == {} // false
0 == null // false
Значение vs Ссылки
Null, undefined, boolean, number, string и ES6 symbol — это простые значения(также известные как примитивы). Они всегда копируют свое содержание в переменную.
Сложные значения всегда создают копию ссылки при присваивании.
var a = 2; // в 'a' присваивается значение равное 2 .
var b = a; // 'b' всегда копирует значение 'a'
b++;
console.log(a); // 2
console.log(b); // 3
var c = [1,2,3];
var d = c; // 'd' это ссылка на общее значение
d.push( 4 ); // Изменяет ссылочное состояние
console.log(c); // [1,2,3,4]
console.log(d); // [1,2,3,4]
/* Сложные значения равны по ссылке*/
var e = [1,2,3,4];
console.log(c === d); // true
console.log(c === e); // false
Чтобы скопировать сложное значение, вам нужно сделать его копию, тогда ссылка не будет указывать на его исходное расположение.
const copy = c.slice() // 'copy' ссылается на новое значение
console.log(c); // [1,2,3,4]
console.log(copy); // [1,2,3,4]
console.log(c === copy); // false
Область видимости
Область видимости задает контекст выполнения. Она определяет доступность значения и функций в коде.
Глобальная область видимости — это самая объемная область. Значения, объявленные вне функций, являются глобальными и могут быть доступны в любой части программы. В браузере объект window является хранилищем глобальной области видимости.
Локальная область видимости — это область заключенная в функцию. Переменные объявленные в локальной области видимости, могут быть доступны только внутри нее.
function outer() {
let a = 1;
function inner() {
let b = 2;
function innermost() {
let c = 3;
console.log(a, b, c); // 1 2 3
}
innermost();
console.log(a, b); // 1 2 — 'c' не объявлена
}
inner();
console.log(a); // 1 — 'b' и 'c' не объявлены
}
outer();
Вы можете думать об областях видимости, как о серии дверей, уменьшающихся по размеру(от самых больших до самых маленьких). Короткий человек, который вписывается в самую маленькую дверь — самую внутреннюю область — также пройдет через любые большие двери — внешние области.
Но, например, высокий человек, который застрял в третьей двери, будет иметь доступ ко всем предыдущим дверям — внешним областям, но не к каким-либо меньшим по размеру дверям — внутренним областям.
Поднятие
Поведение «движущихся» объявлений переменных и функций в верхнюю часть их соответствующих областей на этапе компиляции — называется поднятием.
Объявление функции полностью подняты. Это означает, что объявленная функция может быть вызвана до ее определения.
console.log(toSquare(3)); // 9
function toSquare(n){
return n*n;
}
Переменные частично подняты. Переменные, объявленные с помощью оператора var подняты, но их значения — нет.
let и const не поддерживают подъемы.
{ /* Оригинальный код */
console.log(i); // undefined
var i = 10
console.log(i); // 10
}
{ /* Код этапе фазы компиляции */
var i;
console.log(i); // undefined
i = 10
console.log(i); // 10
}
// ES6 let & const
{
console.log(i); // ReferenceError: i is not defined
const i = 10
console.log(i); // 10
}
{
console.log(i); // ReferenceError: i is not defined
let i = 10
console.log(i); // 10
}
Функциональное выражение vs Функциональное объявление
Функциональные выражения
Функциональное выражение создается, когда исполнение достигает его объявления(оно не является поднятым).
Функциональное объявление
Функциональное объявление может быть вызвано до и после его описания(оно является поднятым).
Переменные: var, let и const
До введения стандарта ES6 переменную можно было объявить только с помощью var. Переменные и функции, объявленные внутри другой функции, не могут быть доступны ни одной из охватывающих областей — они ограничены функциональностью.
Значения объявленные внутри фигурных скобок могут быть использованы и за их пределами.
Примечание. Переменная объявленная без ключевого слова var, let или const создает переменную var в глобальной области.
function greeting() {
console.log(s) // undefined
if(true) {
var s = 'Hi';
undeclaredVar = 'I am automatically created in global scope';
}
console.log(s) // 'Hi'
}
console.log(s); // Error — ReferenceError: s is not defined
greeting();
console.log(undeclaredVar) // 'I am automatically created in global scope'
ES6 let и const являются новыми. Они не подъемные + пара фигурных скобок, в которых они объявлены, ограничивают их область видимости.
let g1 = 'global 1'
let g2 = 'global 2'
{ /* Создаем новый блок кода */
g1 = 'new global 1'
let g2 = 'local global 2'
console.log(g1) // 'new global 1'
console.log(g2) // 'local global 2'
console.log(g3) // ReferenceError: g3 is not defined
let g3 = 'I am not hoisted';
}
console.log(g1) // 'new global 1'
console.log(g2) // 'global 2'
Распространенным заблуждением является то, что const является неизменяемым. Он не может быть переобъявлен, но его значение(если это array/object), на которое он ссылается, может быть изменено!
const tryMe = 'initial assignment';
tryMe = 'this has been reassigned'; // TypeError: Assignment to constant variable.
// Вы не можете переобъявить, но вы можете изменить...
const array = ['Ted', 'is', 'awesome!'];
array[0] = 'Barney';
array[3] = 'Suit up!';
console.log(array); // [“Barney”, “is”, “awesome!”, “Suit up!”]
const airplane = {};
airplane.wings = 2;
airplane.passengers = 200;
console.log(airplane); // {passengers: 200, wings: 2}