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}
Комментарии (26)
ameli_anna_kate
30.12.2017 01:26+1В
Типы и Преобразования
я бы добавила про NaN(not a number), который number, внезапно.
Возможно Infinity и -Infinity
Переменные: var, let и const
Поведение переменных, объявленных с помощью let в цикле for.
А вообще, javascript.ru — не?
mSnus
30.12.2017 06:51Из текста я бы не понял про "Поднятые" функции, если бы не знал про одно- и многопроходную компиляцию.
Из текста не понял, чем let отличается от var. Тем, что они всегда компилируются в один проход?
И этот текст странный:
[quote]Переменные и функции, объявленные внутри другой функции, не могут быть доступны ни одной из охватывающих областей — они ограничены функциональностью[/quote]
Имелось в виду, что все, что объявлено внутри функции, доступно только в ней и недоступно снаружи? А как же автоматически создаваемые глобальные переменные?
Этот справочник внёс сумбур в мои и без того недостаточно четкие знания JS ((
ua9msn
30.12.2017 11:04+2let и const не поддерживают подъемы.
Блистать неверными знаниями — дурной тон. let & const поднимаются!
http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified
ua9msn
30.12.2017 11:09+3Переменная объявленная без ключевого слова var, let или const создает переменную var в глобальной области.
Вы не используете «use strict»;?
Вам еще учиться и учиться, молодой человек. Рановато вам учить других. Не сочтите за брюзжание, сочтите за совет.nrjshka Автор
30.12.2017 11:14-1Это перевод статьи, а не «смотрите какой я умный и сейчас я буду вас учить»
ua9msn
30.12.2017 11:29+1Извините, не заметил что это перевод.
И — боже вас сохрани — не читайте до обедасоветских газетерунды.
Читайте это: JavaScript. Ядро: 2-ое изданиеnrjshka Автор
30.12.2017 11:35-2Не знаю как четче выделить, что это перевод. Целый холлевар пошел из-за того, что статья маленькая.
TheShock
30.12.2017 19:53Не знаю как четче выделить, что это перевод
Вы так говорите, словно то, что это — перевод, оправдывает слабость, унылость и бессмысленность статьиnrjshka Автор
30.12.2017 20:01-2Я это написал, чтобы претензии типа: «Почему нет того, а почему нет этого? А вы знаете, что тут можно добавить еще кое-что?» — сразу же отпадали.
vanxant
31.12.2017 00:53Вы не используете «use strict»;?
Не только в этом дело. Если выше по стеку вложенности функций есть переменная с таким названием, то она будет захвачена замыканием. Соответственно, глобальная переменная не будет создана, а будет загажена эта захваченная переменная.
Это как раз тот случай, когда могут посадить на собеседовании.ua9msn
31.12.2017 08:34Изначально комментарий был к этому утверждению.
Переменная объявленная без ключевого слова var, let или const создает переменную var в глобальной области.
Вы говорите о контексте замыкания а не о глобальном контексте, который, кстати, не только контекст, но и realm, в смысле область исполнения. Нельзя их путать.vanxant
31.12.2017 21:56Я говорю о том, что видя только текст функции с присвоением в необъявленную переменную, невозможно сказать, будет это замыкание или глобальная переменная.
punkkk
30.12.2017 11:22+1На счет const — нельзя изменить значение. Так что неправильно немного сказано. В случае массива\объекта — значение = ссылка, оно не меняется, меняется структура объекта по данной ссылке.
Я увидел, что это перевод, но, получается, перевод неверный, в оригинале:
A common misconception is that const is immutable. It cannot be reassigned, but its properties can be changed!
Kuorell
30.12.2017 11:27+1Раз уж все накинулись про мало.
Я читал полную статью
Там есть
Замыкания
IIFE
Контекст ( тут же arrow functions)
Прототипное наследование (Тут и классы (т.к. в JS это сахар))
Event Loop
sh00tingStar
30.12.2017 11:32+5— Вы ранее привлекались за хранение данных в глобальных переменных?
— Найдите точку G бинарным поиском.
— Вы когда-нибудь делали .Net за деньги?
— Вы способны довести девушку до оргазма языком программирования?
— В своём резюме вы указали знание php. Вам не стыдно?
— Какой из циклов быстрее: for, while или правило буравчика?
— Как часто вы говорите своему коду «ну, пожалуйста...»?
— Вас раньше обвиняли в попытках программирования?
— Можете ли вы провести аналогию между работой на пятилетнем проекте и проктологией?
— Если честно, то нас немного смущает тот факт, что вы искали работу программиста через биржу труда…
— Согласны ли вы, что каждый девелопер должен посадить зрение, построить велосипед и вырастить репозиторий?
— В своем резюме вы указали, что хотели бы поработать на интересном проекте… вы этот проект с собой принесли?
— Скажите, вы когда-нибудь симулировали ООП?
— Каким вы видите свой код через пять лет?
— Вас когда-нибудь запирали в серверной? За что?
— Цой, Ленин, PHP — что между ними общего?
— Как объяснить джуниору что пинговать сервера в его возрасте – это нормально?
— Назовите самое экстремальное место в котором вы занимались багфиксингом
— Напишите простейшую операционную систему. Уложитесь в 140 символов.
Idot
30.12.2017 17:02-3Исчерпывающий справочник по JavaScript для вашего следующего собеседования.
РЕАЛЬНО КРУТО!
Никто случайно, аналогичной стать и про Java незнает?
(просто, по вакансиям сейчас очень много связок PL/SQL+Java, и мне как SQL'щику подобое по Java очень пригодилось бы)
Drag13
Мало.
Из базового:
Нет ничего о замыканиях.
Нет ничего о контексте вызова методов.
Нет ничего о Object.defineProperty()
Нет ничего о наследовании и их видов (я бы не включал но на собесах спрашивают).
Из нового
Нет ничего о стрелочных функциях.
Нет ничего о классах.
Нет ничего о прокси (ладно тут я придираюсь, согласен)
И это так, навскидку.
nrjshka Автор
Спасибо за фидбек.
Да, знаю, что мало, но объем статьи слишком большой, чтобы поместить все в один пост на хабре, поэтому я принял решение, что лучше будет ее разбить на 2 части(в заголовке указано, что это только 1 часть).
Drag13
Это же технический ресурс. Зачем дробить? Искать — не удобно. Читать — не удобно. Еще и комментарии типа «мало». Лучше дополните до полной версии и люди скажут вам спасибо.
babylon
О замыканиях не написал, только ленивый
Чем контекст метода отличается от контекста функции.
и что такое контекст вызова???
Ну нет и что?
Более странно, что на собесах не спрашивают о композиции:) Видимо спрашивающие сами не в курсе.
Ну да удобно
Зачем классы в JS? Контейнеры наше всё.
Это можно пережить. Даже нужно.
Drag13
Напоминаю, название темы звучит
Поэтому ваш комментарий в контексте этой темы непонятен.
nrjshka Автор
А еще стоит напомнить, что это перевод + только первая часть