diff --git a/1-js/2-first-steps/11-uibasic/article.md b/1-js/2-first-steps/11-uibasic/article.md index 357967e6..02c9772e 100644 --- a/1-js/2-first-steps/11-uibasic/article.md +++ b/1-js/2-first-steps/11-uibasic/article.md @@ -51,7 +51,7 @@ alert('Вам ' + years + ' лет!') ``` [warn header="Всегда указывайте `default`"] -Вообще, второй `default` может отсутствовать. Однако при этом IE вставит в диалог значение по умолчанию `"undefined"`. +Второй параметр может отсутствовать. Однако при этом IE вставит в диалог значение по умолчанию `"undefined"`. Запустите этот код в IE, чтобы понять о чем речь: diff --git a/1-js/2-first-steps/13-logical-ops/5-alert-and-or/solution.md b/1-js/2-first-steps/13-logical-ops/5-alert-and-or/solution.md new file mode 100644 index 00000000..e02d8e49 --- /dev/null +++ b/1-js/2-first-steps/13-logical-ops/5-alert-and-or/solution.md @@ -0,0 +1,16 @@ +Ответ: `3`. + +```js +//+ run +alert( null || 2 && 3 || 4 ); +``` + +Приоритет оператора `&&` выше, чем `||`, поэтому он выполнится первым. + +Последовательность вычислений: +``` +null || 2 && 3 || 4 +null || 3 || 4 +3 +``` + diff --git a/1-js/2-first-steps/13-logical-ops/5-alert-and-or/task.md b/1-js/2-first-steps/13-logical-ops/5-alert-and-or/task.md new file mode 100644 index 00000000..9e367c3b --- /dev/null +++ b/1-js/2-first-steps/13-logical-ops/5-alert-and-or/task.md @@ -0,0 +1,10 @@ +# Что выведет этот код? + +[importance 5] + +Что выведет код ниже? + +```js +alert( null || 2 && 3 || 4 ); +``` + diff --git a/1-js/2-first-steps/13-logical-ops/5-check-if-in-range/solution.md b/1-js/2-first-steps/13-logical-ops/6-check-if-in-range/solution.md similarity index 100% rename from 1-js/2-first-steps/13-logical-ops/5-check-if-in-range/solution.md rename to 1-js/2-first-steps/13-logical-ops/6-check-if-in-range/solution.md diff --git a/1-js/2-first-steps/13-logical-ops/5-check-if-in-range/task.md b/1-js/2-first-steps/13-logical-ops/6-check-if-in-range/task.md similarity index 100% rename from 1-js/2-first-steps/13-logical-ops/5-check-if-in-range/task.md rename to 1-js/2-first-steps/13-logical-ops/6-check-if-in-range/task.md diff --git a/1-js/2-first-steps/13-logical-ops/6-check-if-out-range/solution.md b/1-js/2-first-steps/13-logical-ops/7-check-if-out-range/solution.md similarity index 100% rename from 1-js/2-first-steps/13-logical-ops/6-check-if-out-range/solution.md rename to 1-js/2-first-steps/13-logical-ops/7-check-if-out-range/solution.md diff --git a/1-js/2-first-steps/13-logical-ops/6-check-if-out-range/task.md b/1-js/2-first-steps/13-logical-ops/7-check-if-out-range/task.md similarity index 100% rename from 1-js/2-first-steps/13-logical-ops/6-check-if-out-range/task.md rename to 1-js/2-first-steps/13-logical-ops/7-check-if-out-range/task.md diff --git a/1-js/2-first-steps/13-logical-ops/7-if-question/solution.md b/1-js/2-first-steps/13-logical-ops/8-if-question/solution.md similarity index 100% rename from 1-js/2-first-steps/13-logical-ops/7-if-question/solution.md rename to 1-js/2-first-steps/13-logical-ops/8-if-question/solution.md diff --git a/1-js/2-first-steps/13-logical-ops/7-if-question/task.md b/1-js/2-first-steps/13-logical-ops/8-if-question/task.md similarity index 100% rename from 1-js/2-first-steps/13-logical-ops/7-if-question/task.md rename to 1-js/2-first-steps/13-logical-ops/8-if-question/task.md diff --git a/1-js/2-first-steps/13-logical-ops/article.md b/1-js/2-first-steps/13-logical-ops/article.md index 27c01996..bbbcd44a 100644 --- a/1-js/2-first-steps/13-logical-ops/article.md +++ b/1-js/2-first-steps/13-logical-ops/article.md @@ -61,6 +61,7 @@ if (hour < 10 || hour > 18 || isWeekend) { ## Короткий цикл вычислений + JavaScript вычисляет несколько ИЛИ слева направо. При этом, чтобы экономить ресурсы, используется так называемый *"короткий цикл вычисления"*. Допустим, вычисляются несколько ИЛИ подряд: `a || b || c || ...`. Если первый аргумент -- `true`, то результат заведомо будет `true` (хотя бы одно из значений -- `true`), и остальные значения игнорируются. @@ -91,6 +92,11 @@ alert(x); // 1 ## Значение ИЛИ +[quote author="Илья Канатов, участник курса JavaScript"] +`||` запинается на "правде",
+`&&` запинается на "лжи". +[/quote] + Итак, как мы видим, оператор ИЛИ вычисляет ровно столько значений, сколько необходимо -- до первого `true`. При этом оператор ИЛИ возвращает то значение, на котором остановились вычисления. Причём, не преобразованное к логическому типу. @@ -129,9 +135,9 @@ alert( result ); // выведет "Привет!" - первое значени alert( undefined || '' || false || 0 ); // 0 ``` -[summary] Итак, оператор `||` вычисляет операнды слева направо до первого "истинного" и возвращает его, а если все ложные -- то последнее значение. -[/summary] + +Иначе можно сказать, что "`||` запинается на правде". ## && (И) @@ -201,9 +207,9 @@ alert( 1 && 2 && null && 3 ); // null alert( 1 && 2 && 3 ); // 3 ``` -[summary] Итак, оператор `&&` вычисляет операнды слева направо до первого "ложного" и возвращает его, а если все истинные -- то последнее значение. -[/summary] + +Иначе можно сказать, что "`&&` запинается на лжи". [smart header="Приоритет у `&&` больше, чем у `||`"] Приоритет оператора И `&&` больше, чем ИЛИ `||`, так что он выполняется раньше. @@ -262,15 +268,15 @@ var result = !value; ```js //+ run -alert(!true) // false -alert(!0) // true +alert( !true ); // false +alert( !0 ); // true ``` **В частности, двойное НЕ используются для преобразования значений к логическому типу:** ```js //+ run -alert(!!"строка") // true -alert(!!null) // false +alert( !!"строка" ); // true +alert( !!null ); // false ``` diff --git a/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/solution.md b/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/solution.md index 8367d6cf..7441a37f 100644 --- a/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/solution.md +++ b/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/solution.md @@ -16,6 +16,8 @@ true + false = 1 0 || 5 = 5 null + 1 = 1 // (3) undefined + 1 = NaN // (4) +null == "\n0\n" = false // (5) ++null == +"\n0\n" = true // (6) ```
    @@ -23,4 +25,6 @@ undefined + 1 = NaN // (4)
  1. Оператор `"-"` работает только с числами, так что он сразу приводит `""` к `0`.
  2. `null` при численном преобразовании становится `0`
  3. `undefined` при численном преобразовании становится `NaN`
  4. +
  5. При сравнении `==` с `null` преобразования не происходит, есть жёсткое правило: `null == undefined` и только.
  6. +
  7. И левая и правая часть `==` преобразуются к числу `0`.
\ No newline at end of file diff --git a/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/task.md b/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/task.md index 17f99243..6f396866 100644 --- a/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/task.md +++ b/1-js/2-first-steps/14-types-conversion/1-primitive-conversions-questions/task.md @@ -18,5 +18,7 @@ true + false 0 || 5 null + 1 undefined + 1 +null == "\n0\n" ++null == +"\n0\n" ``` diff --git a/1-js/2-first-steps/4-strict-mode/article.md b/1-js/2-first-steps/4-strict-mode/article.md index c828aa28..06320f12 100644 --- a/1-js/2-first-steps/4-strict-mode/article.md +++ b/1-js/2-first-steps/4-strict-mode/article.md @@ -50,7 +50,7 @@ Впрочем, проблема не так страшна. Несовместимостей мало. И, если их знать (а в учебнике мы будем останавливаться на них) и писать правильный код, то всё будет в порядке и `"use strict"` станет нашим верным помощником.
Библиотеки, написанные без учёта `"use strict"`.
-
Некоторые библиотеки, который написаны без `"use strict"`, не всегда корректно работают, если вызывающий код содержит `"use strict"`. +
Некоторые библиотеки, которые написаны без `"use strict"`, не всегда корректно работают, если вызывающий код содержит `"use strict"`. В первую очередь имеются в виду сторонние библиотеки, которые писали не мы, и которые не хотелось бы переписывать или править. diff --git a/1-js/2-first-steps/8-operators/article.md b/1-js/2-first-steps/8-operators/article.md index c2bc826b..bbd526ac 100644 --- a/1-js/2-first-steps/8-operators/article.md +++ b/1-js/2-first-steps/8-operators/article.md @@ -123,23 +123,24 @@ alert( +apples + +oranges ); // 5, число, оба операнда пред Из школы мы знаем, что умножение в выражении `2 * 2 + 1` выполнится раньше сложения, т.к. его *приоритет* выше, а скобки явно задают порядок выполнения. Но в JavaScript -- гораздо больше операторов, поэтому существует целая [таблица приоритетов](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence). -Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число меньше -- выполнится раньше. Если приоритет одинаковый, то порядок выполнения -- слева направо. +Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число больше -- выполнится раньше. Если приоритет одинаковый, то порядок выполнения -- слева направо. Отрывок из таблицы: - - - - - - + + + + + + +
.........
4унарный плюс`+`
4унарный минус`-`
5умножение`*`
5деление`/`
6сложение`+`
6вычитание`-`
15унарный плюс`+`
15унарный минус`-`
14умножение`*`
14деление`/`
13сложение`+`
13вычитание`-`
.........
3присвоение`=`
.........
-Так как "унарный плюс" имеет приоритет `4`, выше, чем `6` у обычного "сложения", то в выражении `+apples + +oranges` сначала сработали плюсы у `apples` и `oranges`, а затем уже обычное сложение. +Так как "унарный плюс" имеет приоритет `15`, выше, чем `13` у обычного "сложения", то в выражении `+apples + +oranges` сначала сработали плюсы у `apples` и `oranges`, а затем уже обычное сложение. ## Присваивание diff --git a/1-js/4-data-structures/11-datetime/2-get-week-day/solution.md b/1-js/4-data-structures/11-datetime/2-get-week-day/solution.md index 40cc5934..29c3e37a 100644 --- a/1-js/4-data-structures/11-datetime/2-get-week-day/solution.md +++ b/1-js/4-data-structures/11-datetime/2-get-week-day/solution.md @@ -14,3 +14,9 @@ var date = new Date(2014, 0, 3); // 3 января 2014 alert( getWeekDay(date) ); // 'пт' ``` +В современных браузерах можно использовать и `toLocaleString`: +```js +//+ run +var date = new Date(2014, 0, 3); // 3 января 2014 +alert( date.toLocaleString('ru', {weekday: 'short'}) ); // 'Пт' +``` \ No newline at end of file diff --git a/1-js/4-data-structures/3-string/4-extract-currency/_js.view/solution.js b/1-js/4-data-structures/3-string/4-extract-currency/_js.view/solution.js new file mode 100644 index 00000000..828030db --- /dev/null +++ b/1-js/4-data-structures/3-string/4-extract-currency/_js.view/solution.js @@ -0,0 +1,3 @@ +function extractCurrencyValue(str) { + return +str.slice(1); +} \ No newline at end of file diff --git a/1-js/4-data-structures/3-string/4-extract-currency/_js.view/test.js b/1-js/4-data-structures/3-string/4-extract-currency/_js.view/test.js new file mode 100644 index 00000000..45e0eb8c --- /dev/null +++ b/1-js/4-data-structures/3-string/4-extract-currency/_js.view/test.js @@ -0,0 +1,8 @@ +describe("extractCurrencyValue", function() { + + it("выделяет из строки $120 число 120", function() { + assert.strictEqual(extractCurrencyValue('$120'), 120); + }); + + +}); \ No newline at end of file diff --git a/1-js/4-data-structures/3-string/4-extract-currency/solution.md b/1-js/4-data-structures/3-string/4-extract-currency/solution.md new file mode 100644 index 00000000..d2c8c1a0 --- /dev/null +++ b/1-js/4-data-structures/3-string/4-extract-currency/solution.md @@ -0,0 +1 @@ +Возьмём часть строки после первого символа и приведём к числу: `+str.slice(1)`. \ No newline at end of file diff --git a/1-js/4-data-structures/3-string/4-extract-currency/task.md b/1-js/4-data-structures/3-string/4-extract-currency/task.md new file mode 100644 index 00000000..ee4691d1 --- /dev/null +++ b/1-js/4-data-structures/3-string/4-extract-currency/task.md @@ -0,0 +1,8 @@ +# Выделить число + +[importance 4] + +Есть стоимость в виде строки: `"$120"`. То есть, первым идёт знак валюты, а затем -- число. + +Создайте функцию `extractCurrencyValue(str)`, которая будет из такой строки выделять число-значение, в данном случае 120. + diff --git a/1-js/4-data-structures/9-array-iteration/article.md b/1-js/4-data-structures/9-array-iteration/article.md index 6cc1e14f..7dee38d7 100644 --- a/1-js/4-data-structures/9-array-iteration/article.md +++ b/1-js/4-data-structures/9-array-iteration/article.md @@ -8,7 +8,7 @@ Метод ["arr.forEach(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) используется для перебора массива. -Он позволяет для каждого элемента массива вызывает функцию `callback`. +Он для каждого элемента массива вызывает функцию `callback`. Этой функции он передаёт три параметра `callback(item, i, arr)`: @@ -64,16 +64,16 @@ alert( positiveArr ); // 1,2,3 ```js //+ run -var pages = ['a.html', 'b.html', 'c.html']; +var names = ['HTML', 'CSS', 'JavaScript']; *!* -var urls = pages.map(function(page) { - return 'http://site.com/' + page; +var nameLengths = names.map(function(name) { + return name.length; }); */!* -// к каждой строке был прибавлен префикс -alert( urls ); // http://site.com/a.html, http://site.com/b.html... +// получили массив с длинами +alert( nameLengths ); // 4,3,10 ``` ## every/some diff --git a/1-js/6-objects-more/1-object-methods/6-return-object-this/solution.md b/1-js/6-objects-more/1-object-methods/6-return-object-this/solution.md index 67dda01b..2df08422 100644 --- a/1-js/6-objects-more/1-object-methods/6-return-object-this/solution.md +++ b/1-js/6-objects-more/1-object-methods/6-return-object-this/solution.md @@ -5,3 +5,22 @@ При создании объекта `{ value: this }`, в свойство `value` копируется ссылка на текущий контекст, то есть на `user`. Получается что `user.export().value == user`. + + +```js +//+ run +var name = ""; + +var user = { + name: "Василий", + + export: function() { + return { + value: this + }; + } + +}; + +alert( user.export().value == user ); // true +``` \ No newline at end of file diff --git a/1-js/6-objects-more/1-object-methods/8-chain-calls/task.md b/1-js/6-objects-more/1-object-methods/8-chain-calls/task.md index fb2a512b..73dc4e8e 100644 --- a/1-js/6-objects-more/1-object-methods/8-chain-calls/task.md +++ b/1-js/6-objects-more/1-object-methods/8-chain-calls/task.md @@ -34,5 +34,7 @@ ladder.showStep(); // 1 ladder.up().up().down().up().down().showStep(); // 1 ``` +Как видно, такая запись содержит "меньше букв" и может быть более наглядной. + Такой подход называется "чейнинг" (chaining) и используется, например, во фреймворке jQuery. diff --git a/1-js/6-objects-more/4-descriptors-getters-setters/article.md b/1-js/6-objects-more/4-descriptors-getters-setters/article.md index 86fd8bbc..32c2ddfb 100644 --- a/1-js/6-objects-more/4-descriptors-getters-setters/article.md +++ b/1-js/6-objects-more/4-descriptors-getters-setters/article.md @@ -9,7 +9,7 @@ Основной метод для управления свойствами -- [Object.defineProperty](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty). -Он позволяет как просто объявить свойство объекта, так и настроить тонко настроить его особые аспекты, которые никак иначе не изменить. +Он позволяет как просто объявить свойство объекта, так и тонко настроить его особые аспекты, которые никак иначе не изменить. Синтаксис: diff --git a/1-js/6-objects-more/7-bind/3-second-bind/solution.md b/1-js/6-objects-more/7-bind/3-second-bind/solution.md index d55561a2..2a8b26d8 100644 --- a/1-js/6-objects-more/7-bind/3-second-bind/solution.md +++ b/1-js/6-objects-more/7-bind/3-second-bind/solution.md @@ -13,7 +13,7 @@ f(); // Вася Первый вызов `f.bind(..Вася..)` возвращает "обёртку", которая устанавливает контекст для `f` и передаёт вызов `f`. -Следующий вызов `bind` будет устанавливать контекст уже для этой обёртки, это ни на что не влияет. +Следующий вызов `bind` будет устанавливать контекст уже для этой обёртки. Это ни на что не повлияет. Чтобы это проще понять, используем наш собственный вариант `bind` вместо встроенного: @@ -45,12 +45,14 @@ f(); // Вася function bind(func, context) { *!* return function() { + // здесь this не используется return func.apply(context, arguments); }; */!* } ``` -В этой обёртке нигде не используется `this`, только `func` и `context`. Посмотрите на код, там нигде нет `this`. +В этой обёртке нигде не используется `this`, контекст `context` берётся из замыкания. Посмотрите на код, там нигде нет `this`. + +Поэтому следующий `bind` в строке `(2)`, который выполняется уже над обёрткой и фиксирует в ней `this`, ни на что не влияет. Какая разница, что будет в качестве `this` в функции, которая этот `this` не использует? Контекст `context`, как видно в коде выше, она получает через замыкание из аргументов первого `bind`. -Поэтому следующий `bind` в строке `(2)`, который выполняется уже над обёрткой и фиксирует в ней `this`, ни на что не влияет. Какая разница, что будет в качестве `this` в функции, которая этот `this` не использует? diff --git a/1-js/6-objects-more/7-bind/article.md b/1-js/6-objects-more/7-bind/article.md index 4af65892..61dae977 100644 --- a/1-js/6-objects-more/7-bind/article.md +++ b/1-js/6-objects-more/7-bind/article.md @@ -12,7 +12,7 @@ В браузере есть встроенная функция `setTimeout(func, ms)`, которая вызывает выполение функции `func` через `ms` миллисекунд (=1/1000 секунды). -Мы подробно остановимся на ней и её тонкостях позже, в главе [](/setTimeout-setInterval), а пока просто посмотрим пример. +Мы подробно остановимся на ней и её тонкостях позже, в главе [](/settimeout-setinterval), а пока просто посмотрим пример. Этот код выведет "Привет" через 1000мс, то есть 1 секунду: diff --git a/1-js/6-objects-more/8-decorators/article.md b/1-js/6-objects-more/8-decorators/article.md index 45604dd9..f089df90 100644 --- a/1-js/6-objects-more/8-decorators/article.md +++ b/1-js/6-objects-more/8-decorators/article.md @@ -53,7 +53,7 @@ alert( timers.myFunc ); // общее время выполнения всех ```js //+ run -var timers = {} +var timers = {}; // прибавит время выполнения f к таймеру timers[timer] function timingDecorator(f, timer) { @@ -114,7 +114,7 @@ function sum(a, b) { alert( sum(true, { name: "Вася", age: 35 }) ); // true[Object object] ``` -Функция "как-то" отработала, но в реальной жизни такой вызов, скорее всего, будет следствием программной ошибки. Всё-таки `sum` предназначена для суммирования чисел, а не объектов. +Функция "как-то" отработала, но в реальной жизни передача в `sum` подобных значений, скорее всего, будет следствием программной ошибки. Всё-таки `sum` предназначена для суммирования чисел, а не объектов. Многие языки программирования позволяют прямо в объявлении функции указать, какие типы данных имеют параметры. И это удобно, поскольку повышает надёжность кода. diff --git a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js index 106b9ca8..48113fa4 100644 --- a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js +++ b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/_js.view/solution.js @@ -3,15 +3,18 @@ function formatDate(date) { // перевести секунды в миллисекунды и преобразовать к Date date = new Date(date * 1000); } else if (typeof date == 'string') { - // разобрать строку и преобразовать к Date - date = date.split('-'); - date = new Date(date[0], date[1] - 1, date[2]); + // строка в стандартном формате автоматически будет разобрана в дату + date = new Date(date); } else if (Array.isArray(date)) { date = new Date(date[0], date[1], date[2]); } // преобразования для поддержки полиморфизма завершены, // теперь мы работаем с датой (форматируем её) + return date.toLocaleString("ru", {day: '2-digit', month: '2-digit', year: '2-digit'}); + + /* + // можно и вручную, если лень добавлят в старый IE поддержку локализации var day = date.getDate(); if (day < 10) day = '0' + day; @@ -23,6 +26,7 @@ function formatDate(date) { if (year < 10) year = '0' + year; var formattedDate = day + '.' + month + '.' + year; - + return formattedDate; + */ } \ No newline at end of file diff --git a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md index 6dcf7974..4d4176da 100644 --- a/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md +++ b/1-js/7-js-misc/1-class-instanceof/1-format-date-polymorphic/task.md @@ -7,7 +7,7 @@ Ее первый аргумент должен содержать дату в одном из видов:
  1. Как объект `Date`.
  2. -
  3. Как строку в формате `yyyy-mm-dd`.
  4. +
  5. Как строку, например `yyyy-mm-dd` или другую в стандартном формате даты.
  6. Как число *секунд* с `01.01.1970`.
  7. Как массив `[гггг, мм, дд]`, месяц начинается с нуля
diff --git a/1-js/7-js-misc/1-class-instanceof/article.md b/1-js/7-js-misc/1-class-instanceof/article.md index f84e41f6..54b519b2 100644 --- a/1-js/7-js-misc/1-class-instanceof/article.md +++ b/1-js/7-js-misc/1-class-instanceof/article.md @@ -53,8 +53,8 @@ alert( toString.call(arr) ); // [object Array] var date = new Date; alert( toString.call(date) ); // [object Date] -var obj = { name: "Вася" }; -alert( toString.call(date) ); // [object Object] +var user = { name: "Вася" }; +alert( toString.call(user) ); // [object Object] ``` В первой строке мы взяли метод `toString`, принадлежащий именно стандартному объекту `{}`. Нам пришлось это сделать, так как у `Date` и `Array` -- свои собственные методы `toString`, которые работают иначе. diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/7-delay/task.md b/1-js/7-js-misc/3-setTimeout-setInterval/7-delay/task.md index 965802ae..f198d7b9 100644 --- a/1-js/7-js-misc/3-setTimeout-setInterval/7-delay/task.md +++ b/1-js/7-js-misc/3-setTimeout-setInterval/7-delay/task.md @@ -2,7 +2,7 @@ [importance 5] -**Напишите функцию `delay(f, ms)`, которая возвращает обёртку вокруг `f`, задерживающую вызов на `ms` миллисекунд.** +Напишите функцию `delay(f, ms)`, которая возвращает обёртку вокруг `f`, задерживающую вызов на `ms` миллисекунд. Например: @@ -18,6 +18,6 @@ f1000("тест"); // выведет "тест" через 1000 миллисек f1500("тест2"); // выведет "тест2" через 1500 миллисекунд ``` -Иначе говоря, `f1000` -- это "задержанный на 1000мс" вызов `f`. +Упрощённо можно сказать, что `delay` возвращает "задержанный на `ms`" вариант `f`. В примере выше у функции только один аргумент, но `delay` должна быть универсальной: передавать любое количество аргументов и контекст `this`. \ No newline at end of file diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/8-debounce/task.md b/1-js/7-js-misc/3-setTimeout-setInterval/8-debounce/task.md index 37d11c8b..31b9f540 100644 --- a/1-js/7-js-misc/3-setTimeout-setInterval/8-debounce/task.md +++ b/1-js/7-js-misc/3-setTimeout-setInterval/8-debounce/task.md @@ -2,7 +2,7 @@ [importance 5] -**Напишите функцию `debounce(f, ms)`, которая возвращает обёртку, которая передаёт вызов `f` не чаще, чем раз в `ms` миллисекунд.** +Напишите функцию `debounce(f, ms)`, которая возвращает обёртку, которая передаёт вызов `f` не чаще, чем раз в `ms` миллисекунд. "Лишние" вызовы игнорируются. Все аргументы и контекст -- передаются. @@ -22,3 +22,4 @@ setTimeout( function() { f(4) }, 1100); // выполнится setTimeout( function() { f(5) }, 1500); // игнор ``` +Упрощённо можно сказать, что `debounce` возвращает вариант `f`, срабатывающий не чаще чем раз в `ms` миллисекунд. \ No newline at end of file diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/9-throttle/task.md b/1-js/7-js-misc/3-setTimeout-setInterval/9-throttle/task.md index 367cd92c..aaf5956b 100644 --- a/1-js/7-js-misc/3-setTimeout-setInterval/9-throttle/task.md +++ b/1-js/7-js-misc/3-setTimeout-setInterval/9-throttle/task.md @@ -27,7 +27,7 @@
  • Первое обновление произойдёт сразу (это важно, посетитель тут же видит реакцию на своё действие).
  • Дальше может быть много вызовов (микро-передвижений) с разными координатами, но пока не пройдёт 100мс -- ничего не будет.
  • По истечении 100мс -- опять обновление, с последними координатами. Промежуточные микро-передвижения игнорированы.
  • -
  • В конце концов мышь где-то остановится, обновление по окончании очередной паузы 100мс (иначе мы не знаем, последнее оно или нет) сработает с последними координатами.
  • +
  • В конце концов мышь где-то остановится, обновление по окончании очередной паузы 100мс сработает с последними координатами.
  • Ещё раз заметим -- задача из реальной жизни, и в ней принципиально важно, что *последнее* передвижение обрабатывается. Пользователь должен увидеть, где остановил мышь. diff --git a/1-js/7-js-misc/3-setTimeout-setInterval/article.md b/1-js/7-js-misc/3-setTimeout-setInterval/article.md index 64c3412a..9da49c8d 100644 --- a/1-js/7-js-misc/3-setTimeout-setInterval/article.md +++ b/1-js/7-js-misc/3-setTimeout-setInterval/article.md @@ -239,7 +239,7 @@ setTimeout(function() {}, 100); Позапускайте его в различных браузерах. Вы заметите, что несколько первых полосок анимируются с одинаковой скоростью. Это как раз потому, что слишком маленькие задержки таймер не различает. -[iframe border="1" src="setInterval-anim" link edit] +[iframe border="1" src="setinterval-anim" link edit] [warn] В Internet Explorer, нулевая задержка `setInterval(.., 0)` не сработает. Это касается именно `setInterval`, т.е. `setTimeout(.., 0)` работает нормально. diff --git a/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/solution.md b/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/solution.md index e81a19bd..19384566 100644 --- a/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/solution.md +++ b/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/solution.md @@ -1,39 +1,17 @@ Ошибка -- в том, что метод `walk` присваивается в конструкторе `Animal` самому объекту вместо прототипа. -Казалось бы -- ничего страшного, ведь `Animal.apply(this, arguments)` создаст его. Код работает. - -Однако, если мы решим перезаписать этот метод своим, специфичным для кролика, то будет сюрприз: +Поэтому, если мы решим перезаписать этот метод своим, специфичным для кролика, то он не сработает: ```js -//+ run -function Animal(name) { - this.name = name; +// ... - this.walk = function() { - alert( "ходит " + this.name ); - }; -} - -function Rabbit(name) { - Animal.apply(this, arguments); -} -Rabbit.prototype = Object.create(Animal.prototype); - -*!* +// записывается в прототип Rabbit.prototype.walk = function() { - alert( "прыгает! и ходит: " + this.name ); + alert( "прыгает " + this.name ); }; -*/!* - -var rabbit = new Rabbit("Кроль"); -*!* -rabbit.walk(); // ходит Кроль -*/!* ``` -Переопределение не сработало! - -Причина -- метод `walk` создаётся в конструкторе, записывается в сам объект и тем самым игнорирует цепочку прототипов и говорит "гуд-бай" всей иерархии наследования. +Метод `this.walk` из `Animal` записывается в сам объект, и поэтому он всегда будет первым, игнорируя цепочку прототипов. Правильно было бы определять `walk` как `Animal.prototype.walk`. diff --git a/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/task.md b/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/task.md index 90c9588d..eabfb7f6 100644 --- a/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/task.md +++ b/1-js/9-prototypes/5-class-inheritance/2-inheritance-error-constructor/task.md @@ -20,6 +20,10 @@ function Rabbit(name) { } Rabbit.prototype = Object.create(Animal.prototype); +Rabbit.prototype.walk = function() { + alert( "прыгает " + this.name ); +}; + var rabbit = new Rabbit("Кроль"); rabbit.walk(); ``` diff --git a/1-js/9-prototypes/6-instanceof/article.md b/1-js/9-prototypes/6-instanceof/article.md index 05407303..2a427d72 100644 --- a/1-js/9-prototypes/6-instanceof/article.md +++ b/1-js/9-prototypes/6-instanceof/article.md @@ -77,7 +77,7 @@ alert( rabbit instanceof Rabbit ); // false Вообще, у каждого окна и фрейма -- своя иерархия объектов и свой `window` . -Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства `[[Class]]`. Более подробно это описано в главе [](/class-property). +Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства `[[Class]]`, которое подробнее описано в главе [](/class-instanceof). [/warn] diff --git a/1-js/9-prototypes/7-oop-errors/article.md b/1-js/9-prototypes/7-oop-errors/article.md index f97825e8..22134ca1 100644 --- a/1-js/9-prototypes/7-oop-errors/article.md +++ b/1-js/9-prototypes/7-oop-errors/article.md @@ -210,7 +210,7 @@ function PropertyRequiredError(property) { this.message = 'Отсутствует свойство ' + property; } -PropertyRequiredError.prototype = Object.create(PropertyError); +PropertyRequiredError.prototype = Object.create(PropertyError.prototype); PropertyRequiredError.prototype.constructor = PropertyRequiredError; var err = new PropertyRequiredError("age"); diff --git a/10-extra/5-setImmediate/article.md b/10-extra/5-setImmediate/article.md index 93d16318..123ece3e 100644 --- a/10-extra/5-setImmediate/article.md +++ b/10-extra/5-setImmediate/article.md @@ -49,6 +49,6 @@ if (!window.setImmediate) window.setImmediate = (function() { Чтобы сравнить реальную частоту срабатывания -- измерим время на 100 последовательных вызовов при `setTimeout(..0)` по сравнению с `setImmediate`: -[codetabs src="setImmediate"] +[codetabs src="setimmediate"] Запустите пример выше -- и вы увидите реальную разницу во времени между `setTimeout(.., 0)` и `setImmediate`. Да, она может быть более в 50, 100 и более раз. \ No newline at end of file diff --git a/2-ui/1-document/18-coordinates-document/article.md b/2-ui/1-document/18-coordinates-document/article.md index eb3831d3..9e25fc76 100644 --- a/2-ui/1-document/18-coordinates-document/article.md +++ b/2-ui/1-document/18-coordinates-document/article.md @@ -135,7 +135,7 @@ function getOffsetSum(elem) { [pre]
    -
    Кликните, чтобы получить координаты getOffsetSum и getCoords
    +
    Кликните, чтобы получить координаты getOffsetSum и getCoords
    diff --git a/2-ui/1-document/4-traversing-dom/1-dom-children/task.md b/2-ui/1-document/4-traversing-dom/1-dom-children/task.md index a0bfb3ca..21e85842 100644 --- a/2-ui/1-document/4-traversing-dom/1-dom-children/task.md +++ b/2-ui/1-document/4-traversing-dom/1-dom-children/task.md @@ -36,4 +36,3 @@
  • Напишите код, который получит второй `LI`. Будет ли ваш код работать в IE8-, если комментарий переместить *между* элементами `LI`?
  • -[edit src="solution" task/] \ No newline at end of file diff --git a/2-ui/1-document/7-basic-dom-node-properties/4-where-document-in-hierarchy/solution.md b/2-ui/1-document/7-basic-dom-node-properties/4-where-document-in-hierarchy/solution.md new file mode 100644 index 00000000..d27accb7 --- /dev/null +++ b/2-ui/1-document/7-basic-dom-node-properties/4-where-document-in-hierarchy/solution.md @@ -0,0 +1,72 @@ + +Объектом какого класса является `document`, можно выяснить так: +```js +//+ run +alert(document); // [object HTMLDocument] +``` + +Или так: +```js +//+ run +alert(document.constructor); // function HTMLDocument() { ... } +``` + +Итак, `document` -- объект класса `HTMLDocument`. + +Какое место `HTMLDocument` занимает в иерархии? + +Можно поискать в документации. Но попробуем выяснить это самостоятельно. + +Вопрос не такой простой и требует хорошего понимания [прототипного наследования](/class-inheritance). + +Вспомним, как оно устроено: + + +При поиске свойства в `document`, если его там нет, оно ищется в `document.__proto__`, затем в `document.__proto__.__proto__` и так далее, пока не найдём, или пока цепочка `__proto__` не закончится. Это обычное устройство класса, без наследования. + +Нам нужно лишь узнать, что находится в этих самых `__proto__`. + +Строго говоря, там могут быть любые объекты. Вовсе не обязательно, чтобы объектам из цепочки прототипов соответствовали какие-то конструкторы. + +Вполне может быть цепочка, где родители -- просто обычные JS-объекты: +```js +document -> HTMLDocument.prototype -> obj1 -> obj2 -> ... +``` + +Однако, здесь мы знаем, что наследование -- "на классах", то есть, эти объекты `obj1`, `obj2` являются `prototype` неких функций-конструкторов: + +```js +document -> HTMLDocument.prototype -> F1.prototype -> F2.prototype -> ... +``` + +Что стоит на месте `F1`, `F2`? + +Опять же, если говорить про некие абстрактные объекты, то откуда нам знать, какие функции на них ссылаются через `prototype`? Ниоткуда. Один объект может быть в `prototype` хоть у десятка функций. + +Но в стандартном прототипном наследовании один объект является `prototype` ровно у одной функции. Причём при создании функции в её `prototype` уже есть объект со свойством `constructor`, которое ссылается обратно на функцию: +```js +F.prototype = { constructor: F } +``` + +Это свойство `constructor`, если конечно его не удалить или не перезаписать нечаянно (чего делать не следует), и позволяет из прототипа узнать соответствующий ему конструктор. + +```js +//+ run +// цепочка наследования: +alert(HTMLDocument.prototype.constructor); // function HTMLDocument +alert(HTMLDocument.prototype.__proto__.constructor); // function Document +alert(HTMLDocument.prototype.__proto__.__proto__.constructor); // function Node +``` + +При выводе объекта через `console.dir(document)` в Google Chrome, мы тоже можем, раскрывая `__proto__`, увидеть эти названия (`HTMLDocument`, `Document`, `Node`). + +Браузерная консоль их берёт как раз из свойства `constructor`. + + + + + diff --git a/2-ui/1-document/7-basic-dom-node-properties/4-where-document-in-hierarchy/task.md b/2-ui/1-document/7-basic-dom-node-properties/4-where-document-in-hierarchy/task.md new file mode 100644 index 00000000..517eeb3a --- /dev/null +++ b/2-ui/1-document/7-basic-dom-node-properties/4-where-document-in-hierarchy/task.md @@ -0,0 +1,11 @@ +# Где в DOM-иерархии document? + +[importance 4] +Объектом какого класса является `document`? + +Какое место он занимает в DOM-иерархии? + +Наследует ли он `Node` или `Element`? + +Воспользуйтесь для решения тем фактом, что DOM-узлы образуют стандартную прототипную иерархию классов. + diff --git a/2-ui/1-document/7-basic-dom-node-properties/article.md b/2-ui/1-document/7-basic-dom-node-properties/article.md index b67e96b8..0bb288f2 100644 --- a/2-ui/1-document/7-basic-dom-node-properties/article.md +++ b/2-ui/1-document/7-basic-dom-node-properties/article.md @@ -38,35 +38,57 @@ alert( document.body ); // [object HTMLBodyElement] ``` -Детальное описание свойств и методов каждого DOM-класса дано в [спецификации](http://www.whatwg.org/specs/web-apps/current-work/multipage/). - -Например, [The input element](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element) описывает класс, соответствующий ``, включая [interface HTMLInputElement](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#htmlinputelement), который нас как раз и интересует. - -Вот из него выдержка: +Можно и проверить при помощи `instanceof`: ```js -interface HTMLInputElement: HTMLElement { +//+ run +alert( document.body instanceof HTMLBodyElement ); // true +alert( document.body instanceof HTMLElement ); // true +alert( document.body instanceof Element ); // true +alert( document.body instanceof Node ); // true +``` + +Как видно, DOM-узлы -- обычные JavaScript-объекты. Их классы заданы в прототипном стиле. В этом легко убедиться, если вывести в консоли любой элемент через `console.dir(elem)`. Или даже можно напрямую обратиться к методам, которые хранятся в `Node.prototype`, `Element.prototype` и так далее. + +[smart header="`console.dir(elem)` против `console.log(elem)`"] +Вывод `console.log(elem)` и `console.dir(elem)` различен. + + +Попробуйте сами на `document.body`. +[/smart] + +Детальное описание свойств и методов каждого DOM-класса дано в [спецификации](https://html.spec.whatwg.org/multipage/). + +Например, [The input element](https://html.spec.whatwg.org/multipage/forms.html#the-input-element) описывает класс, соответствующий ``, включая [interface HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement), который нас как раз и интересует. + +При описании свойств и методов используется не JavaScript, а специальный язык [IDL](https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%BE%D0%B2) (Interface Definition Language), который достаточно легко понять "с ходу". + +Вот из него выдержка, с комментариями: + +```js +// Объявлен HTMLInputElement +// двоеточие означает, что он наследует от HTMLElement +interface HTMLInputElement: HTMLElement { + + // у всех таких элементов есть строковые свойства + // accept, alt, autocomplete, value attribute DOMString accept; attribute DOMString alt; attribute DOMString autocomplete; + attribute DOMString value; + + // и логическое свойство autofocus attribute boolean autofocus; ... - attribute DOMString value; - ... + // а также метод select, который значение не возвращает (void) void select(); ... } ``` -При описании свойств и методов используется не JavaScript, а специальный язык [IDL](https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%BE%D0%B2) (Interface Definition Language), который достаточно легко понять "с ходу". - -В частности, выше мы видим, что: - - Далее в этом разделе мы поговорим о самых главных свойствах узлов DOM, которые используются наиболее часто. ## Тип: nodeType @@ -83,7 +105,7 @@ interface HTMLInputElement: HTMLElement { ```js interface Node { - // NodeType + // Всевозможные значения nodeType const unsigned short ELEMENT_NODE = 1; const unsigned short ATTRIBUTE_NODE = 2; const unsigned short TEXT_NODE = 3; @@ -277,7 +299,7 @@ chatDiv.innerHTML += "Как дела?"; В примере закрывающий тег `` разбит на две строки, т.к. иначе браузер подумает, что это конец скрипта. Вставленный скрипт не выполнится. -Исключение -- IE9-, в нем вставляемый скрипт выполняются, если у него есть атрибут `defer`. Но это нестандартная возможность, которой не следует пользоваться. +Исключение -- IE9-, в нем вставляемый скрипт выполняются, если у него есть атрибут `defer`. Но это нестандартная возможность, которой не следует пользоваться. [/warn] @@ -447,9 +469,9 @@ chatDiv.innerHTML += "Как дела?"; Как правило, видим или невидим узел, определяется через CSS, свойствами `display` или `visibility`. -В стандарте HTML5 предусмотрен специальный атрибут (он же свойство) для этого: `hidden`. +В стандарте HTML5 предусмотрен специальный атрибут и свойство для этого: `hidden`. -Его поддерживают все современные браузеры, кроме старых IE. +Его поддерживают все современные браузеры, кроме IE10-. В примере ниже второй и третий `
    ` скрыты: diff --git a/2-ui/2-events-and-interfaces/2-events-and-timing-depth/article.md b/2-ui/2-events-and-interfaces/2-events-and-timing-depth/article.md index 831bd230..4c01ab74 100644 --- a/2-ui/2-events-and-interfaces/2-events-and-timing-depth/article.md +++ b/2-ui/2-events-and-interfaces/2-events-and-timing-depth/article.md @@ -1,6 +1,6 @@ # Порядок обработки событий -События могут возникать не только по очереди, но и "пачкой" по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для `onclick` -- посетитель провёл мышкой, а это уже `mousemove`. +События могут возникать не только по очереди, но и "пачкой" по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для `onclick` -- посетитель нажал кнопку на клавиатуре (событие `keydown`). Здесь мы разберём, как браузер обычно работает с одновременно возникающими событиями и какие есть исключения из общего правила. @@ -50,8 +50,8 @@ В действии: ```html - -
    Количество запросов: 0
    diff --git a/figures.sketch b/figures.sketch index efa5014c..a8230c12 100644 Binary files a/figures.sketch and b/figures.sketch differ