Async / Defer
Браузер загружает и отображает HTML постепенно. Особенно это заметно при медленном интернет-соединении: браузер не ждёт, пока страница загрузится целиком, а показывает ту часть, которую успел загрузить.
Если браузер видит тег
<script>, то он по стандарту обязан сначала выполнить его, а потом показать оставшуюся часть страницы.
Такое поведение называют «синхронным». Как правило, оно вполне нормально, но есть важное следствие.
Если скрипт – внешний, то пока браузер не выполнит его, он не покажет часть страницы под ним.
И здесь вопрос – действительно ли мы этого хотим? То есть, действительно ли оставшуюся часть страницы нельзя показывать до загрузки скрипта?
Атрибут
И здесь вопрос – действительно ли мы этого хотим? То есть, действительно ли оставшуюся часть страницы нельзя показывать до загрузки скрипта?
Атрибут
async
Поддерживается всеми браузерами, кроме IE9-. Скрипт выполняется полностью асинхронно. То есть, при обнаружении
<script async src="..."> браузер не останавливает обработку страницы, а спокойно работает дальше. Когда скрипт будет загружен – он выполнится.defer
Поддерживается всеми браузерами, включая самые старые IE. Скрипт также выполняется асинхронно, не заставляет ждать страницу, но есть два отличия от
async.
Первое – браузер гарантирует, что относительный порядок скриптов с
defer будет сохранён.
То есть, в таком коде (с
async) первым сработает тот скрипт, который раньше загрузится:<script src="1.js" async></script>
<script src="2.js" async></script>
А в таком коде (с
defer) первым сработает всегда 1.js, а скрипт 2.js, даже если загрузился раньше, будет его ждать.<script src="1.js" defer></script>
<script src="2.js" defer></script>
Поэтому атрибут
defer используют в тех случаях, когда второй скрипт 2.js зависит от первого 1.js, к примеру – использует что-то, описанное первым скриптом.
Второе отличие – скрипт с
defer сработает, когда весь HTML-документ будет обработан браузером.
Например, если документ достаточно большой…
<script src="async.js" async></script>
<script src="defer.js" defer></script>
Много много много букв
…То скрипт
async.js выполнится, как только загрузится – возможно, до того, как весь документ готов. А defer.js подождёт готовности всего документа.
Это бывает удобно, когда мы в скрипте хотим работать с документом, и должны быть уверены, что он полностью получен.
Итого:
- Скрипты вставляются на страницу как текст в теге
<script>, либо как внешний файл через<script src="путь"></script> - Специальные атрибуты
asyncиdeferиспользуются для того, чтобы пока грузится внешний скрипт – браузер показал остальную (следующую за ним) часть страницы. Без них этого не происходит. - Разница между
asyncиdefer: атрибутdeferсохраняет относительную последовательность скриптов, аasync– нет. Кроме того,deferвсегда ждёт, пока весь HTML-документ будет готов, аasync– нет.
Use Strict
Если говорить абстрактно, то – да, нужен. В строгом режиме исправлены некоторые ошибки в дизайне языка, и вообще, современный стандарт – это хорошо.
Use strict также можно указывать в начале функций, тогда строгий режим будет действовать только внутри функции.
В старом стандарте JavaScript разрешалось создавать переменную и без
var, просто присвоив ей значение:num = 5; // переменная num будет создана, если ее не было
В режиме
"use strict" так делать уже нельзя.Var / Let / Const
У объявлений переменной через
let есть три основных отличия от var:- Область видимости переменной
let– блок{...}.Как мы помним, переменная, объявленная черезvar, видна везде в функции.Переменная, объявленная черезlet, видна только в рамках блока{...}, в котором объявлена.Это, в частности, влияет на объявления внутриif,whileилиfor.Например, переменная черезvar:var apples = 5; if (true) { var apples = 10; alert(apples); // 10 (внутри блока) } alert(apples); // 10 (снаружи блока то же самое)В примере вышеapples– одна переменная на весь код, которая модифицируется вif.То же самое сletбудет работать по-другому:let apples = 5; // (*) if (true) { let apples = 10; alert(apples); // 10 (внутри блока) } alert(apples); // 5 (снаружи блока значение не изменилось)Здесь, фактически, две независимые переменныеapples, одна – глобальная, вторая – в блокеif.Заметим, что если объявлениеlet applesв первой строке(*)удалить, то в последнемalertбудет ошибка: переменная не определена.
Это потому что переменнаяletвсегда видна именно в том блоке, где объявлена, и не более. - Переменная
letвидна только после объявления.Как мы помним, переменныеvarсуществуют и до объявления. Они равныundefined:alert(a); // undefined var a = 5;С переменнымиletвсё проще. До объявления их вообще нет.Такой доступ приведёт к ошибке:alert(a); // ошибка, нет такой переменной let a = 5;Заметим также, что переменныеletнельзя повторно объявлять. То есть, такой код выведет ошибку:let x; let x; // ошибка: переменная x уже объявленаЭто – хоть и выглядит ограничением по сравнению сvar, но на самом деле проблем не создаёт. Например, два таких цикла совсем не конфликтуют:// каждый цикл имеет свою переменную i for(let i = 0; i<10; i++) { /* … */ } for(let i = 0; i<10; i++) { /* … */ } alert( i ); // ошибка: глобальной i нетПри объявлении внутри цикла переменнаяiбудет видна только в блоке цикла. Она не видна снаружи, поэтому будет ошибка в последнемalert. - При использовании в цикле, для каждой итерации создаётся своя переменная.Переменная
var– одна на все итерации цикла и видна даже после цикла:for(var i=0; i<10; i++) { /* … */ } alert(i); // 10С переменнойlet– всё по-другому.Каждому повторению цикла соответствует своя независимая переменнаяlet. Если внутри цикла есть вложенные объявления функций, то в замыкании каждой будет та переменная, которая была при соответствующей итерации.Это позволяет легко решить классическую проблему с замыканиями, описанную в задаче Армия функций.function makeArmy() { let shooters = []; for (let i = 0; i < 10; i++) { shooters.push(function() { alert( i ); // выводит свой номер }); } return shooters; } var army = makeArmy(); army[0](); // 0 army[5](); // 5Если бы объявление былоvar i, то была бы одна переменнаяiна всю функцию, и вызовы в последних строках выводили бы10(подробнее – см. задачу Армия функций).А выше объявлениеlet iсоздаёт для каждого повторения блока в цикле свою переменную, которую функция и получает из замыкания в последних строках.
const
Объявление
const задаёт константу, то есть переменную, которую нельзя менять:const apple = 5;
apple = 10; // ошибка
В остальном объявление
const полностью аналогично let.
Заметим, что если в константу присвоен объект, то от изменения защищена сама константа, но не свойства внутри неё:
const user = {
name: "Вася"
};
user.name = "Петя"; // допустимо
user = 5; // нельзя, будет ошибка
То же самое верно, если константе присвоен массив или другое объектное значение.
константы и КОНСТАНТЫ
Константы, которые жёстко заданы всегда, во время всей программы, обычно пишутся в верхнем регистре. Например:
const ORANGE = "#ffa500".
Большинство переменных – константы в другом смысле: они не меняются после присвоения. Но при разных запусках функции это значение может быть разным. Для таких переменных можно использовать
const и обычные строчные буквы в имени.Итого
Переменные
let:- Видны только после объявления и только в текущем блоке.
- Нельзя переобъявлять (в том же блоке).
- При объявлении переменной в цикле
for(let …)– она видна только в этом цикле. Причём каждой итерации соответствует своя переменнаяlet.
Переменная
const – это константа, в остальном – как let.Alert / Confirm / Prompt
alertвыводит сообщение.promptвыводит сообщение и ждёт, пока пользователь введёт текст, а затем возвращает введённое значение илиnull, если ввод отменён (CANCEL/Esc).confirmвыводит сообщение и ждёт, пока пользователь нажмёт «OK» или «CANCEL» и возвращаетtrue/false.
If / Else / Else if
Краткая форма
условие ? значение1 : значение2
Switch
Конструкция
switch заменяет собой сразу несколько if.
Она представляет собой более наглядный способ сравнить выражение сразу с несколькими вариантами.
Синтаксис
Выглядит она так:
switch(x) {
case 'value1': // if (x === 'value1')
...
[break]
case 'value2': // if (x === 'value2')
...
[break]
default:
...
[break]
}
- Переменная
xпроверяется на строгое равенство первому значениюvalue1, затем второмуvalue2и так далее. - Если соответствие установлено – switch начинает выполняться от соответствующей директивы
caseи далее, до ближайшегоbreak(или до концаswitch). - Если ни один
caseне совпал – выполняется (если есть) вариантdefault.
При этом
case называют вариантами switch.
Если
break нет, то выполнение пойдёт ниже по следующим case, при этом остальные проверки игнорируются.
Пример без
break:var a = 2 + 2; switch (a) { case 3: alert( 'Маловато' ); case 4: alert( 'В точку!' ); case 5: alert( 'Перебор' ); default: alert( 'Я таких значений не знаю' ); }
В примере выше последовательно выполнятся три
alert:alert( 'В точку!' );
alert( 'Перебор' );
alert( 'Я таких значений не знаю' );
В
case могут быть любые выражения, в том числе включающие в себя переменные и функции.
Например:
var a = 1; var b = 0; switch (a) { case b + 1: alert( 1 ); break; default: alert('нет-нет, выполнится вариант выше') }
Группировка case
Несколько значений case можно группировать.
В примере ниже
case 3 и case 5 выполняют один и тот же код:var a = 2+2; switch (a) { case 4: alert('Верно!'); break; case 3: // (*) case 5: // (**) alert('Неверно!'); alert('Немного ошиблись, бывает.'); break; default: alert('Странный результат, очень странный'); }
При
case 3 выполнение идёт со строки (*), при case 5 – со строки (**).
Следующий пример принимает значение от посетителя.
var arg = prompt("Введите arg?")
switch (arg) {
case '0':
case '1':
alert( 'Один или ноль' );
case '2':
alert( 'Два' );
break;
case 3:
alert( 'Никогда не выполнится' );
default:
alert('Неизвестное значение: ' + arg)
}
Что оно выведет при вводе числа 0? Числа 1? 2? 3?
Подумайте, выпишите свои ответы, исходя из текущего понимания работы
switch и потом читайте дальше…- При вводе
0выполнится первыйalert, далее выполнение продолжится вниз до первогоbreakи выведет второйalert('Два'). Итого, два выводаalert. - При вводе
1произойдёт то же самое. - При вводе
2,switchперейдет кcase '2', и сработает единственныйalert('Два'). - При вводе
3,switchперейдет наdefault. Это потому, чтоpromptвозвращает строку'3', а не число. Типы разные. Операторswitchпредполагает строгое равенство===, так что совпадения не будет.
For
Чаще всего применяется цикл
for. Выглядит он так:for (начало; условие; шаг) {
// ... тело цикла ...
}
Пример цикла, который выполняет
alert(i) для i от 0 до 2 включительно (до 3):var i;
for (i = 0; i < 3; i++) {
alert( i );
}
Здесь:
- Начало:
i=0. - Условие:
i<3. - Шаг:
i++. - Тело:
alert(i), т.е. код внутри фигурных скобок (они не обязательны, если только одна операция)
Цикл выполняется так:
- Начало:
i=0выполняется один-единственный раз, при заходе в цикл. - Условие:
i<3проверяется перед каждой итерацией и при входе в цикл, если оно нарушено, то происходит выход. - Тело:
alert(i). - Шаг:
i++выполняется после тела на каждой итерации, но перед проверкой условия. - Идти на шаг 2.
Иными словами, поток выполнения:
начало → (если условие → тело → шаг) → (если условие → тело → шаг) → … и так далее, пока верно условие.Пропуск частей for
Любая часть
for может быть пропущена.
Например, можно убрать
начало. Цикл в примере ниже полностью идентичен приведённому выше:var i = 0;
for (; i < 3; i++) {
alert( i ); // 0, 1, 2
}
Можно убрать и
шаг:var i = 0;
for (; i < 3;) {
alert( i );
// цикл превратился в аналог while (i<3)
}
А можно и вообще убрать всё, получив бесконечный цикл:
for (;;) {
// будет выполняться вечно
}
При этом сами точки с запятой
; обязательно должны присутствовать, иначе будет ошибка синтаксиса.Прерывание цикла: break
Выйти из цикла можно не только при проверке условия но и, вообще, в любой момент. Эту возможность обеспечивает директива
break.
Например, следующий код подсчитывает сумму вводимых чисел до тех пор, пока посетитель их вводит, а затем – выдаёт:
var sum = 0; while (true) { var value = +prompt("Введите число", ''); if (!value) break; // (*) sum += value; } alert( 'Сумма: ' + sum );
Директива
break в строке (*), если посетитель ничего не ввёл, полностью прекращает выполнение цикла и передаёт управление на строку за его телом, то есть на alert.
Вообще, сочетание «бесконечный цикл + break» – отличная штука для тех ситуаций, когда условие, по которому нужно прерваться, находится не в начале-конце цикла, а посередине.
Следующая итерация: continue
Директива
continue прекращает выполнение текущей итерации цикла.
Она – в некотором роде «младшая сестра» директивы
break: прерывает не весь цикл, а только текущее выполнение его тела, как будто оно закончилось.
Её используют, если понятно, что на текущем повторе цикла делать больше нечего.
Например, цикл ниже использует
continue, чтобы не выводить чётные значения:
for (var i = 0; i < 10; i++) {
if (i % 2 == 0) continue;
alert(i);
}
Для чётных
i срабатывает continue, выполнение тела прекращается и управление передаётся на следующий проход for.
Директива
continue позволяет обойтись без скобок
Цикл, который обрабатывает только нечётные значения, мог бы выглядеть так:
for (var i = 0; i < 10; i++) {
if (i % 2) {
alert( i );
}
}
С технической точки зрения он полностью идентичен. Действительно, вместо
continue можно просто завернуть действия в блок if. Однако, мы получили дополнительный уровень вложенности фигурных скобок. Если код внутри ifболее длинный, то это ухудшает читаемость, в отличие от варианта с continue.For...in / For...of
Цикл for...in проходит через перечисляемые свойства объекта. Он пройдёт по каждому отдельному элементу.
Цикл
for...in проходит только по перечисляемым свойствам. Объекты, созданные встроенными конструкторами, такими как Array и Object имеют неперечисляемые свойства от Object.prototype и String.prototype, например, от String-это indexOf(), а от Object - метод toString(). Цикл пройдёт по всем перечисляемым свойствам объекта, а также тем, что он унаследует от конструктора прототипа (свойства объекта в цепи прототипа).
Оператор
for...of выполняет цикл обхода итерируемых объектов (включая Array, Map, Set, объект аргументов и подобных), вызывая на каждом шаге итерации операторы для каждого значения из различных свойств объекта..ForEach()
Метод
forEach() выполняет указанную функцию один раз для каждого элемента в массиве.
Метод
forEach() выполняет функцию callback один раз для каждого элемента, находящегося в массиве в порядке возрастания. Она не будет вызвана для удалённых или пропущенных элементов массива. Однако, она будет вызвана для элементов, которые присутствуют в массиве и имеют значение undefined.
Функция
callback будет вызвана с тремя аргументами:- значение элемента (value)
- индекс элемента (index)
- массив, по которому осуществляется проход (array)
Если в метод
forEach() был передан параметр thisArg, при вызове callback он будет использоваться в качестве значения this. В противном случае, в качестве значения this будет использоваться значение undefined. В конечном итоге, значение this, наблюдаемое из функции callback, определяется согласно обычным правилам определения this, видимого из функции.
Диапазон элементов, обрабатываемых методом
forEach(), устанавливается до первого вызова функции callback. Элементы, добавленные в массив после начала выполнения метода forEach(), не будут посещены функцией callback. Если существующие элементы массива изменятся, значения, переданные в функцию callback, будут значениями на тот момент времени, когда метод forEach() посетит их; удалённые элементы посещены не будут.While / Do...While
Цикл
while имеет вид:while (условие) {
// код, тело цикла
}
Пока
условие верно – выполняется код из тела цикла.Цикл do…while
Проверку условия можно поставить под телом цикла, используя специальный синтаксис
do..while:do {
// тело цикла
} while (условие);
Цикл, описанный, таким образом, сначала выполняет тело, а затем проверяет условие.
Например:
var i = 0;
do {
alert( i );
i++;
} while (i < 3);
Синтаксис
do..while редко используется, т.к. обычный while нагляднее – в нём не приходится искать глазами условие и ломать голову, почему оно проверяется именно в конце.isNaN()
Функция
isNaN() определяет является ли литерал или переменная не числовым значением (NaN) или нет. При работе с функцией необходимо проявлять осторожность так как она работает некорректно. Если вам интересно подробнее можно посмотреть Number.isNaN() то как она описана в ECMAScript 6, в качестве альтернативного решения можно использовать typeof для проверки литерала или переменной на не числовое значение.parseInt() / parseFloat()
Функция
parseInt() принимает строку в качестве аргумента и возвращает целое число в соответствии с указанным основанием системы счисления.
Функция
parseFloat() принимает строку в качестве аргумента и возвращает десятичное число (число с плавающей точкой)toString()
МетодtoString() возвращает строку, представляющую объект..length
Length свойство объекта, который является экземпляром вида Array , устанавливает или возвращает число элементов в этом массиве. Значение безнаковое 32 битное целое число, которое всегда численно больше чем самый наибольший индекс в массиве.
Комментариев нет:
Отправить комментарий