renovations
This commit is contained in:
parent
0e9ceb2b3a
commit
150d92f10f
47 changed files with 290 additions and 110 deletions
|
@ -51,7 +51,7 @@ alert('Вам ' + years + ' лет!')
|
||||||
```
|
```
|
||||||
|
|
||||||
[warn header="Всегда указывайте `default`"]
|
[warn header="Всегда указывайте `default`"]
|
||||||
Вообще, второй `default` может отсутствовать. Однако при этом IE вставит в диалог значение по умолчанию `"undefined"`.
|
Второй параметр может отсутствовать. Однако при этом IE вставит в диалог значение по умолчанию `"undefined"`.
|
||||||
|
|
||||||
Запустите этот код <u>в IE</u>, чтобы понять о чем речь:
|
Запустите этот код <u>в IE</u>, чтобы понять о чем речь:
|
||||||
|
|
||||||
|
|
16
1-js/2-first-steps/13-logical-ops/5-alert-and-or/solution.md
Normal file
16
1-js/2-first-steps/13-logical-ops/5-alert-and-or/solution.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
Ответ: `3`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
alert( null || 2 && 3 || 4 );
|
||||||
|
```
|
||||||
|
|
||||||
|
Приоритет оператора `&&` выше, чем `||`, поэтому он выполнится первым.
|
||||||
|
|
||||||
|
Последовательность вычислений:
|
||||||
|
```
|
||||||
|
null || 2 && 3 || 4
|
||||||
|
null || 3 || 4
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
10
1-js/2-first-steps/13-logical-ops/5-alert-and-or/task.md
Normal file
10
1-js/2-first-steps/13-logical-ops/5-alert-and-or/task.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Что выведет этот код?
|
||||||
|
|
||||||
|
[importance 5]
|
||||||
|
|
||||||
|
Что выведет код ниже?
|
||||||
|
|
||||||
|
```js
|
||||||
|
alert( null || 2 && 3 || 4 );
|
||||||
|
```
|
||||||
|
|
|
@ -61,6 +61,7 @@ if (hour < 10 || hour > 18 || isWeekend) {
|
||||||
|
|
||||||
## Короткий цикл вычислений
|
## Короткий цикл вычислений
|
||||||
|
|
||||||
|
|
||||||
JavaScript вычисляет несколько ИЛИ слева направо. При этом, чтобы экономить ресурсы, используется так называемый *"короткий цикл вычисления"*.
|
JavaScript вычисляет несколько ИЛИ слева направо. При этом, чтобы экономить ресурсы, используется так называемый *"короткий цикл вычисления"*.
|
||||||
|
|
||||||
Допустим, вычисляются несколько ИЛИ подряд: `a || b || c || ...`. Если первый аргумент -- `true`, то результат заведомо будет `true` (хотя бы одно из значений -- `true`), и остальные значения игнорируются.
|
Допустим, вычисляются несколько ИЛИ подряд: `a || b || c || ...`. Если первый аргумент -- `true`, то результат заведомо будет `true` (хотя бы одно из значений -- `true`), и остальные значения игнорируются.
|
||||||
|
@ -91,6 +92,11 @@ alert(x); // 1
|
||||||
|
|
||||||
## Значение ИЛИ
|
## Значение ИЛИ
|
||||||
|
|
||||||
|
[quote author="Илья Канатов, участник курса JavaScript"]
|
||||||
|
`||` запинается на "правде",<br>
|
||||||
|
`&&` запинается на "лжи".
|
||||||
|
[/quote]
|
||||||
|
|
||||||
Итак, как мы видим, оператор ИЛИ вычисляет ровно столько значений, сколько необходимо -- до первого `true`.
|
Итак, как мы видим, оператор ИЛИ вычисляет ровно столько значений, сколько необходимо -- до первого `true`.
|
||||||
|
|
||||||
При этом оператор ИЛИ возвращает то значение, на котором остановились вычисления. Причём, не преобразованное к логическому типу.
|
При этом оператор ИЛИ возвращает то значение, на котором остановились вычисления. Причём, не преобразованное к логическому типу.
|
||||||
|
@ -129,9 +135,9 @@ alert( result ); // выведет "Привет!" - первое значени
|
||||||
alert( undefined || '' || false || 0 ); // 0
|
alert( undefined || '' || false || 0 ); // 0
|
||||||
```
|
```
|
||||||
|
|
||||||
[summary]
|
|
||||||
Итак, оператор `||` вычисляет операнды слева направо до первого "истинного" и возвращает его, а если все ложные -- то последнее значение.
|
Итак, оператор `||` вычисляет операнды слева направо до первого "истинного" и возвращает его, а если все ложные -- то последнее значение.
|
||||||
[/summary]
|
|
||||||
|
Иначе можно сказать, что "`||` запинается на правде".
|
||||||
|
|
||||||
## && (И)
|
## && (И)
|
||||||
|
|
||||||
|
@ -201,9 +207,9 @@ alert( 1 && 2 && null && 3 ); // null
|
||||||
alert( 1 && 2 && 3 ); // 3
|
alert( 1 && 2 && 3 ); // 3
|
||||||
```
|
```
|
||||||
|
|
||||||
[summary]
|
|
||||||
Итак, оператор `&&` вычисляет операнды слева направо до первого "ложного" и возвращает его, а если все истинные -- то последнее значение.
|
Итак, оператор `&&` вычисляет операнды слева направо до первого "ложного" и возвращает его, а если все истинные -- то последнее значение.
|
||||||
[/summary]
|
|
||||||
|
Иначе можно сказать, что "`&&` запинается на лжи".
|
||||||
|
|
||||||
[smart header="Приоритет у `&&` больше, чем у `||`"]
|
[smart header="Приоритет у `&&` больше, чем у `||`"]
|
||||||
Приоритет оператора И `&&` больше, чем ИЛИ `||`, так что он выполняется раньше.
|
Приоритет оператора И `&&` больше, чем ИЛИ `||`, так что он выполняется раньше.
|
||||||
|
@ -262,15 +268,15 @@ var result = !value;
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
alert(!true) // false
|
alert( !true ); // false
|
||||||
alert(!0) // true
|
alert( !0 ); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
**В частности, двойное НЕ используются для преобразования значений к логическому типу:**
|
**В частности, двойное НЕ используются для преобразования значений к логическому типу:**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
alert(!!"строка") // true
|
alert( !!"строка" ); // true
|
||||||
alert(!!null) // false
|
alert( !!null ); // false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ true + false = 1
|
||||||
0 || 5 = 5
|
0 || 5 = 5
|
||||||
null + 1 = 1 // (3)
|
null + 1 = 1 // (3)
|
||||||
undefined + 1 = NaN // (4)
|
undefined + 1 = NaN // (4)
|
||||||
|
null == "\n0\n" = false // (5)
|
||||||
|
+null == +"\n0\n" = true // (6)
|
||||||
```
|
```
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
|
@ -23,4 +25,6 @@ undefined + 1 = NaN // (4)
|
||||||
<li>Оператор `"-"` работает только с числами, так что он сразу приводит `""` к `0`.</li>
|
<li>Оператор `"-"` работает только с числами, так что он сразу приводит `""` к `0`.</li>
|
||||||
<li>`null` при численном преобразовании становится `0`</li>
|
<li>`null` при численном преобразовании становится `0`</li>
|
||||||
<li>`undefined` при численном преобразовании становится `NaN`</li>
|
<li>`undefined` при численном преобразовании становится `NaN`</li>
|
||||||
|
<li>При сравнении `==` с `null` преобразования не происходит, есть жёсткое правило: `null == undefined` и только.</li>
|
||||||
|
<li>И левая и правая часть `==` преобразуются к числу `0`.</li>
|
||||||
</ol>
|
</ol>
|
|
@ -18,5 +18,7 @@ true + false
|
||||||
0 || 5
|
0 || 5
|
||||||
null + 1
|
null + 1
|
||||||
undefined + 1
|
undefined + 1
|
||||||
|
null == "\n0\n"
|
||||||
|
+null == +"\n0\n"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
Впрочем, проблема не так страшна. Несовместимостей мало. И, если их знать (а в учебнике мы будем останавливаться на них) и писать правильный код, то всё будет в порядке и `"use strict"` станет нашим верным помощником.
|
Впрочем, проблема не так страшна. Несовместимостей мало. И, если их знать (а в учебнике мы будем останавливаться на них) и писать правильный код, то всё будет в порядке и `"use strict"` станет нашим верным помощником.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Библиотеки, написанные без учёта `"use strict"`.</dt>
|
<dt>Библиотеки, написанные без учёта `"use strict"`.</dt>
|
||||||
<dd>Некоторые библиотеки, который написаны без `"use strict"`, не всегда корректно работают, если вызывающий код содержит `"use strict"`.
|
<dd>Некоторые библиотеки, которые написаны без `"use strict"`, не всегда корректно работают, если вызывающий код содержит `"use strict"`.
|
||||||
|
|
||||||
В первую очередь имеются в виду сторонние библиотеки, которые писали не мы, и которые не хотелось бы переписывать или править.
|
В первую очередь имеются в виду сторонние библиотеки, которые писали не мы, и которые не хотелось бы переписывать или править.
|
||||||
|
|
||||||
|
|
|
@ -123,23 +123,24 @@ alert( +apples + +oranges ); // 5, число, оба операнда пред
|
||||||
|
|
||||||
Из школы мы знаем, что умножение в выражении `2 * 2 + 1` выполнится раньше сложения, т.к. его *приоритет* выше, а скобки явно задают порядок выполнения. Но в JavaScript -- гораздо больше операторов, поэтому существует целая [таблица приоритетов](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence).
|
Из школы мы знаем, что умножение в выражении `2 * 2 + 1` выполнится раньше сложения, т.к. его *приоритет* выше, а скобки явно задают порядок выполнения. Но в JavaScript -- гораздо больше операторов, поэтому существует целая [таблица приоритетов](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence).
|
||||||
|
|
||||||
Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число меньше -- выполнится раньше. Если приоритет одинаковый, то порядок выполнения -- слева направо.
|
Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число больше -- выполнится раньше. Если приоритет одинаковый, то порядок выполнения -- слева направо.
|
||||||
|
|
||||||
Отрывок из таблицы:
|
Отрывок из таблицы:
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr><td>...</td><td>...</td><td>...</td></tr>
|
<tr><td>...</td><td>...</td><td>...</td></tr>
|
||||||
<tr><td>4</td><td>унарный плюс</td><td>`+`</td></tr>
|
<tr><td>15</td><td>унарный плюс</td><td>`+`</td></tr>
|
||||||
<tr><td>4</td><td>унарный минус</td><td>`-`</td></tr>
|
<tr><td>15</td><td>унарный минус</td><td>`-`</td></tr>
|
||||||
<tr><td>5</td><td>умножение</td><td>`*`</td></tr>
|
<tr><td>14</td><td>умножение</td><td>`*`</td></tr>
|
||||||
<tr><td>5</td><td>деление</td><td>`/`</td></tr>
|
<tr><td>14</td><td>деление</td><td>`/`</td></tr>
|
||||||
<tr><td>6</td><td>сложение</td><td>`+`</td></tr>
|
<tr><td>13</td><td>сложение</td><td>`+`</td></tr>
|
||||||
<tr><td>6</td><td>вычитание</td><td>`-`</td></tr>
|
<tr><td>13</td><td>вычитание</td><td>`-`</td></tr>
|
||||||
|
<tr><td>...</td><td>...</td><td>...</td></tr>
|
||||||
<tr><td>3</td><td>присвоение</td><td>`=`</td></tr>
|
<tr><td>3</td><td>присвоение</td><td>`=`</td></tr>
|
||||||
<tr><td>...</td><td>...</td><td>...</td></tr>
|
<tr><td>...</td><td>...</td><td>...</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
Так как "унарный плюс" имеет приоритет `4`, выше, чем `6` у обычного "сложения", то в выражении `+apples + +oranges` сначала сработали плюсы у `apples` и `oranges`, а затем уже обычное сложение.
|
Так как "унарный плюс" имеет приоритет `15`, выше, чем `13` у обычного "сложения", то в выражении `+apples + +oranges` сначала сработали плюсы у `apples` и `oranges`, а затем уже обычное сложение.
|
||||||
|
|
||||||
## Присваивание
|
## Присваивание
|
||||||
|
|
||||||
|
|
|
@ -14,3 +14,9 @@ var date = new Date(2014, 0, 3); // 3 января 2014
|
||||||
alert( getWeekDay(date) ); // 'пт'
|
alert( getWeekDay(date) ); // 'пт'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
В современных браузерах можно использовать и `toLocaleString`:
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
var date = new Date(2014, 0, 3); // 3 января 2014
|
||||||
|
alert( date.toLocaleString('ru', {weekday: 'short'}) ); // 'Пт'
|
||||||
|
```
|
|
@ -0,0 +1,3 @@
|
||||||
|
function extractCurrencyValue(str) {
|
||||||
|
return +str.slice(1);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
describe("extractCurrencyValue", function() {
|
||||||
|
|
||||||
|
it("выделяет из строки $120 число 120", function() {
|
||||||
|
assert.strictEqual(extractCurrencyValue('$120'), 120);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
Возьмём часть строки после первого символа и приведём к числу: `+str.slice(1)`.
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Выделить число
|
||||||
|
|
||||||
|
[importance 4]
|
||||||
|
|
||||||
|
Есть стоимость в виде строки: `"$120"`. То есть, первым идёт знак валюты, а затем -- число.
|
||||||
|
|
||||||
|
Создайте функцию `extractCurrencyValue(str)`, которая будет из такой строки выделять число-значение, в данном случае 120.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
Метод ["arr.forEach(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) используется для перебора массива.
|
Метод ["arr.forEach(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) используется для перебора массива.
|
||||||
|
|
||||||
Он позволяет для каждого элемента массива вызывает функцию `callback`.
|
Он для каждого элемента массива вызывает функцию `callback`.
|
||||||
|
|
||||||
Этой функции он передаёт три параметра `callback(item, i, arr)`:
|
Этой функции он передаёт три параметра `callback(item, i, arr)`:
|
||||||
|
|
||||||
|
@ -64,16 +64,16 @@ alert( positiveArr ); // 1,2,3
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
var pages = ['a.html', 'b.html', 'c.html'];
|
var names = ['HTML', 'CSS', 'JavaScript'];
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
var urls = pages.map(function(page) {
|
var nameLengths = names.map(function(name) {
|
||||||
return 'http://site.com/' + page;
|
return name.length;
|
||||||
});
|
});
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
// к каждой строке был прибавлен префикс
|
// получили массив с длинами
|
||||||
alert( urls ); // http://site.com/a.html, http://site.com/b.html...
|
alert( nameLengths ); // 4,3,10
|
||||||
```
|
```
|
||||||
|
|
||||||
## every/some
|
## every/some
|
||||||
|
|
|
@ -5,3 +5,22 @@
|
||||||
При создании объекта `{ value: this }`, в свойство `value` копируется ссылка на текущий контекст, то есть на `user`.
|
При создании объекта `{ value: this }`, в свойство `value` копируется ссылка на текущий контекст, то есть на `user`.
|
||||||
|
|
||||||
Получается что `user.export().value == user`.
|
Получается что `user.export().value == user`.
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
var name = "";
|
||||||
|
|
||||||
|
var user = {
|
||||||
|
name: "Василий",
|
||||||
|
|
||||||
|
export: function() {
|
||||||
|
return {
|
||||||
|
value: this
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
alert( user.export().value == user ); // true
|
||||||
|
```
|
|
@ -34,5 +34,7 @@ ladder.showStep(); // 1
|
||||||
ladder.up().up().down().up().down().showStep(); // 1
|
ladder.up().up().down().up().down().showStep(); // 1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Как видно, такая запись содержит "меньше букв" и может быть более наглядной.
|
||||||
|
|
||||||
Такой подход называется "чейнинг" (chaining) и используется, например, во фреймворке jQuery.
|
Такой подход называется "чейнинг" (chaining) и используется, например, во фреймворке jQuery.
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
Основной метод для управления свойствами -- [Object.defineProperty](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty).
|
Основной метод для управления свойствами -- [Object.defineProperty](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty).
|
||||||
|
|
||||||
Он позволяет как просто объявить свойство объекта, так и настроить тонко настроить его особые аспекты, которые никак иначе не изменить.
|
Он позволяет как просто объявить свойство объекта, так и тонко настроить его особые аспекты, которые никак иначе не изменить.
|
||||||
|
|
||||||
Синтаксис:
|
Синтаксис:
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ f(); // Вася
|
||||||
|
|
||||||
Первый вызов `f.bind(..Вася..)` возвращает "обёртку", которая устанавливает контекст для `f` и передаёт вызов `f`.
|
Первый вызов `f.bind(..Вася..)` возвращает "обёртку", которая устанавливает контекст для `f` и передаёт вызов `f`.
|
||||||
|
|
||||||
Следующий вызов `bind` будет устанавливать контекст уже для этой обёртки, это ни на что не влияет.
|
Следующий вызов `bind` будет устанавливать контекст уже для этой обёртки. Это ни на что не повлияет.
|
||||||
|
|
||||||
Чтобы это проще понять, используем наш собственный вариант `bind` вместо встроенного:
|
Чтобы это проще понять, используем наш собственный вариант `bind` вместо встроенного:
|
||||||
|
|
||||||
|
@ -45,12 +45,14 @@ f(); // Вася
|
||||||
function bind(func, context) {
|
function bind(func, context) {
|
||||||
*!*
|
*!*
|
||||||
return function() {
|
return function() {
|
||||||
|
// здесь this не используется
|
||||||
return func.apply(context, arguments);
|
return func.apply(context, arguments);
|
||||||
};
|
};
|
||||||
*/!*
|
*/!*
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
В этой обёртке нигде не используется `this`, только `func` и `context`. Посмотрите на код, там нигде нет `this`.
|
В этой обёртке нигде не используется `this`, контекст `context` берётся из замыкания. Посмотрите на код, там нигде нет `this`.
|
||||||
|
|
||||||
|
Поэтому следующий `bind` в строке `(2)`, который выполняется уже над обёрткой и фиксирует в ней `this`, ни на что не влияет. Какая разница, что будет в качестве `this` в функции, которая этот `this` не использует? Контекст `context`, как видно в коде выше, она получает через замыкание из аргументов первого `bind`.
|
||||||
|
|
||||||
Поэтому следующий `bind` в строке `(2)`, который выполняется уже над обёрткой и фиксирует в ней `this`, ни на что не влияет. Какая разница, что будет в качестве `this` в функции, которая этот `this` не использует?
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
В браузере есть встроенная функция `setTimeout(func, ms)`, которая вызывает выполение функции `func` через `ms` миллисекунд (=1/1000 секунды).
|
В браузере есть встроенная функция `setTimeout(func, ms)`, которая вызывает выполение функции `func` через `ms` миллисекунд (=1/1000 секунды).
|
||||||
|
|
||||||
Мы подробно остановимся на ней и её тонкостях позже, в главе [](/setTimeout-setInterval), а пока просто посмотрим пример.
|
Мы подробно остановимся на ней и её тонкостях позже, в главе [](/settimeout-setinterval), а пока просто посмотрим пример.
|
||||||
|
|
||||||
Этот код выведет "Привет" через 1000мс, то есть 1 секунду:
|
Этот код выведет "Привет" через 1000мс, то есть 1 секунду:
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ alert( timers.myFunc ); // общее время выполнения всех
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
var timers = {}
|
var timers = {};
|
||||||
|
|
||||||
// прибавит время выполнения f к таймеру timers[timer]
|
// прибавит время выполнения f к таймеру timers[timer]
|
||||||
function timingDecorator(f, timer) {
|
function timingDecorator(f, timer) {
|
||||||
|
@ -114,7 +114,7 @@ function sum(a, b) {
|
||||||
alert( sum(true, { name: "Вася", age: 35 }) ); // true[Object object]
|
alert( sum(true, { name: "Вася", age: 35 }) ); // true[Object object]
|
||||||
```
|
```
|
||||||
|
|
||||||
Функция "как-то" отработала, но в реальной жизни такой вызов, скорее всего, будет следствием программной ошибки. Всё-таки `sum` предназначена для суммирования чисел, а не объектов.
|
Функция "как-то" отработала, но в реальной жизни передача в `sum` подобных значений, скорее всего, будет следствием программной ошибки. Всё-таки `sum` предназначена для суммирования чисел, а не объектов.
|
||||||
|
|
||||||
Многие языки программирования позволяют прямо в объявлении функции указать, какие типы данных имеют параметры. И это удобно, поскольку повышает надёжность кода.
|
Многие языки программирования позволяют прямо в объявлении функции указать, какие типы данных имеют параметры. И это удобно, поскольку повышает надёжность кода.
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,18 @@ function formatDate(date) {
|
||||||
// перевести секунды в миллисекунды и преобразовать к Date
|
// перевести секунды в миллисекунды и преобразовать к Date
|
||||||
date = new Date(date * 1000);
|
date = new Date(date * 1000);
|
||||||
} else if (typeof date == 'string') {
|
} else if (typeof date == 'string') {
|
||||||
// разобрать строку и преобразовать к Date
|
// строка в стандартном формате автоматически будет разобрана в дату
|
||||||
date = date.split('-');
|
date = new Date(date);
|
||||||
date = new Date(date[0], date[1] - 1, date[2]);
|
|
||||||
} else if (Array.isArray(date)) {
|
} else if (Array.isArray(date)) {
|
||||||
date = new Date(date[0], date[1], date[2]);
|
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();
|
var day = date.getDate();
|
||||||
if (day < 10) day = '0' + day;
|
if (day < 10) day = '0' + day;
|
||||||
|
|
||||||
|
@ -25,4 +28,5 @@ function formatDate(date) {
|
||||||
var formattedDate = day + '.' + month + '.' + year;
|
var formattedDate = day + '.' + month + '.' + year;
|
||||||
|
|
||||||
return formattedDate;
|
return formattedDate;
|
||||||
|
*/
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@
|
||||||
Ее первый аргумент должен содержать дату в одном из видов:
|
Ее первый аргумент должен содержать дату в одном из видов:
|
||||||
<ol>
|
<ol>
|
||||||
<li>Как объект `Date`.</li>
|
<li>Как объект `Date`.</li>
|
||||||
<li>Как строку в формате `yyyy-mm-dd`.</li>
|
<li>Как строку, например `yyyy-mm-dd` или другую в стандартном формате даты.</li>
|
||||||
<li>Как число *секунд* с `01.01.1970`.</li>
|
<li>Как число *секунд* с `01.01.1970`.</li>
|
||||||
<li>Как массив `[гггг, мм, дд]`, месяц начинается с нуля</li>
|
<li>Как массив `[гггг, мм, дд]`, месяц начинается с нуля</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
|
@ -53,8 +53,8 @@ alert( toString.call(arr) ); // [object Array]
|
||||||
var date = new Date;
|
var date = new Date;
|
||||||
alert( toString.call(date) ); // [object Date]
|
alert( toString.call(date) ); // [object Date]
|
||||||
|
|
||||||
var obj = { name: "Вася" };
|
var user = { name: "Вася" };
|
||||||
alert( toString.call(date) ); // [object Object]
|
alert( toString.call(user) ); // [object Object]
|
||||||
```
|
```
|
||||||
|
|
||||||
В первой строке мы взяли метод `toString`, принадлежащий именно стандартному объекту `{}`. Нам пришлось это сделать, так как у `Date` и `Array` -- свои собственные методы `toString`, которые работают иначе.
|
В первой строке мы взяли метод `toString`, принадлежащий именно стандартному объекту `{}`. Нам пришлось это сделать, так как у `Date` и `Array` -- свои собственные методы `toString`, которые работают иначе.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[importance 5]
|
[importance 5]
|
||||||
|
|
||||||
**Напишите функцию `delay(f, ms)`, которая возвращает обёртку вокруг `f`, задерживающую вызов на `ms` миллисекунд.**
|
Напишите функцию `delay(f, ms)`, которая возвращает обёртку вокруг `f`, задерживающую вызов на `ms` миллисекунд.
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
|
@ -18,6 +18,6 @@ f1000("тест"); // выведет "тест" через 1000 миллисек
|
||||||
f1500("тест2"); // выведет "тест2" через 1500 миллисекунд
|
f1500("тест2"); // выведет "тест2" через 1500 миллисекунд
|
||||||
```
|
```
|
||||||
|
|
||||||
Иначе говоря, `f1000` -- это "задержанный на 1000мс" вызов `f`.
|
Упрощённо можно сказать, что `delay` возвращает "задержанный на `ms`" вариант `f`.
|
||||||
|
|
||||||
В примере выше у функции только один аргумент, но `delay` должна быть универсальной: передавать любое количество аргументов и контекст `this`.
|
В примере выше у функции только один аргумент, но `delay` должна быть универсальной: передавать любое количество аргументов и контекст `this`.
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[importance 5]
|
[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); // игнор
|
setTimeout( function() { f(5) }, 1500); // игнор
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Упрощённо можно сказать, что `debounce` возвращает вариант `f`, срабатывающий не чаще чем раз в `ms` миллисекунд.
|
|
@ -27,7 +27,7 @@
|
||||||
<li>Первое обновление произойдёт сразу (это важно, посетитель тут же видит реакцию на своё действие).</li>
|
<li>Первое обновление произойдёт сразу (это важно, посетитель тут же видит реакцию на своё действие).</li>
|
||||||
<li>Дальше может быть много вызовов (микро-передвижений) с разными координатами, но пока не пройдёт 100мс -- ничего не будет.</li>
|
<li>Дальше может быть много вызовов (микро-передвижений) с разными координатами, но пока не пройдёт 100мс -- ничего не будет.</li>
|
||||||
<li>По истечении 100мс -- опять обновление, с последними координатами. Промежуточные микро-передвижения игнорированы.</li>
|
<li>По истечении 100мс -- опять обновление, с последними координатами. Промежуточные микро-передвижения игнорированы.</li>
|
||||||
<li>В конце концов мышь где-то остановится, обновление по окончании очередной паузы 100мс (иначе мы не знаем, последнее оно или нет) сработает с последними координатами.</li>
|
<li>В конце концов мышь где-то остановится, обновление по окончании очередной паузы 100мс сработает с последними координатами.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
Ещё раз заметим -- задача из реальной жизни, и в ней принципиально важно, что *последнее* передвижение обрабатывается. Пользователь должен увидеть, где остановил мышь.
|
Ещё раз заметим -- задача из реальной жизни, и в ней принципиально важно, что *последнее* передвижение обрабатывается. Пользователь должен увидеть, где остановил мышь.
|
||||||
|
|
|
@ -239,7 +239,7 @@ setTimeout(function() {}, 100);
|
||||||
|
|
||||||
Позапускайте его в различных браузерах. Вы заметите, что несколько первых полосок анимируются с одинаковой скоростью. Это как раз потому, что слишком маленькие задержки таймер не различает.
|
Позапускайте его в различных браузерах. Вы заметите, что несколько первых полосок анимируются с одинаковой скоростью. Это как раз потому, что слишком маленькие задержки таймер не различает.
|
||||||
|
|
||||||
[iframe border="1" src="setInterval-anim" link edit]
|
[iframe border="1" src="setinterval-anim" link edit]
|
||||||
|
|
||||||
[warn]
|
[warn]
|
||||||
В Internet Explorer, нулевая задержка `setInterval(.., 0)` не сработает. Это касается именно `setInterval`, т.е. `setTimeout(.., 0)` работает нормально.
|
В Internet Explorer, нулевая задержка `setInterval(.., 0)` не сработает. Это касается именно `setInterval`, т.е. `setTimeout(.., 0)` работает нормально.
|
||||||
|
|
|
@ -1,39 +1,17 @@
|
||||||
Ошибка -- в том, что метод `walk` присваивается в конструкторе `Animal` самому объекту вместо прототипа.
|
Ошибка -- в том, что метод `walk` присваивается в конструкторе `Animal` самому объекту вместо прототипа.
|
||||||
|
|
||||||
Казалось бы -- ничего страшного, ведь `Animal.apply(this, arguments)` создаст его. Код работает.
|
Поэтому, если мы решим перезаписать этот метод своим, специфичным для кролика, то он не сработает:
|
||||||
|
|
||||||
Однако, если мы решим перезаписать этот метод своим, специфичным для кролика, то будет сюрприз:
|
|
||||||
|
|
||||||
```js
|
```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() {
|
Rabbit.prototype.walk = function() {
|
||||||
alert( "прыгает! и ходит: " + this.name );
|
alert( "прыгает " + this.name );
|
||||||
};
|
};
|
||||||
*/!*
|
|
||||||
|
|
||||||
var rabbit = new Rabbit("Кроль");
|
|
||||||
*!*
|
|
||||||
rabbit.walk(); // ходит Кроль
|
|
||||||
*/!*
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Переопределение не сработало!
|
Метод `this.walk` из `Animal` записывается в сам объект, и поэтому он всегда будет первым, игнорируя цепочку прототипов.
|
||||||
|
|
||||||
Причина -- метод `walk` создаётся в конструкторе, записывается в сам объект и тем самым игнорирует цепочку прототипов и говорит "гуд-бай" всей иерархии наследования.
|
|
||||||
|
|
||||||
Правильно было бы определять `walk` как `Animal.prototype.walk`.
|
Правильно было бы определять `walk` как `Animal.prototype.walk`.
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,10 @@ function Rabbit(name) {
|
||||||
}
|
}
|
||||||
Rabbit.prototype = Object.create(Animal.prototype);
|
Rabbit.prototype = Object.create(Animal.prototype);
|
||||||
|
|
||||||
|
Rabbit.prototype.walk = function() {
|
||||||
|
alert( "прыгает " + this.name );
|
||||||
|
};
|
||||||
|
|
||||||
var rabbit = new Rabbit("Кроль");
|
var rabbit = new Rabbit("Кроль");
|
||||||
rabbit.walk();
|
rabbit.walk();
|
||||||
```
|
```
|
||||||
|
|
|
@ -77,7 +77,7 @@ alert( rabbit instanceof Rabbit ); // false
|
||||||
|
|
||||||
Вообще, у каждого окна и фрейма -- своя иерархия объектов и свой `window` .
|
Вообще, у каждого окна и фрейма -- своя иерархия объектов и свой `window` .
|
||||||
|
|
||||||
Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства `[[Class]]`. Более подробно это описано в главе [](/class-property).
|
Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства `[[Class]]`, которое подробнее описано в главе [](/class-instanceof).
|
||||||
[/warn]
|
[/warn]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,7 @@ function PropertyRequiredError(property) {
|
||||||
this.message = 'Отсутствует свойство ' + property;
|
this.message = 'Отсутствует свойство ' + property;
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyRequiredError.prototype = Object.create(PropertyError);
|
PropertyRequiredError.prototype = Object.create(PropertyError.prototype);
|
||||||
PropertyRequiredError.prototype.constructor = PropertyRequiredError;
|
PropertyRequiredError.prototype.constructor = PropertyRequiredError;
|
||||||
|
|
||||||
var err = new PropertyRequiredError("age");
|
var err = new PropertyRequiredError("age");
|
||||||
|
|
|
@ -49,6 +49,6 @@ if (!window.setImmediate) window.setImmediate = (function() {
|
||||||
|
|
||||||
Чтобы сравнить реальную частоту срабатывания -- измерим время на 100 последовательных вызовов при `setTimeout(..0)` по сравнению с `setImmediate`:
|
Чтобы сравнить реальную частоту срабатывания -- измерим время на 100 последовательных вызовов при `setTimeout(..0)` по сравнению с `setImmediate`:
|
||||||
|
|
||||||
[codetabs src="setImmediate"]
|
[codetabs src="setimmediate"]
|
||||||
|
|
||||||
Запустите пример выше -- и вы увидите реальную разницу во времени между `setTimeout(.., 0)` и `setImmediate`. Да, она может быть более в 50, 100 и более раз.
|
Запустите пример выше -- и вы увидите реальную разницу во времени между `setTimeout(.., 0)` и `setImmediate`. Да, она может быть более в 50, 100 и более раз.
|
|
@ -135,7 +135,7 @@ function getOffsetSum(elem) {
|
||||||
[pre]
|
[pre]
|
||||||
<div style="position:relative;padding:10px;height:80px;width:380px;border:7px red solid">
|
<div style="position:relative;padding:10px;height:80px;width:380px;border:7px red solid">
|
||||||
<div style="border:10px blue solid;padding:2px;position:absolute;left:20%;top:20%">
|
<div style="border:10px blue solid;padding:2px;position:absolute;left:20%;top:20%">
|
||||||
<div id="getBoundingClientRectEx" style="background-color:yellow;border:4px solid black;margin:2px;cursor:pointer">Кликните, чтобы получить координаты getOffsetSum и getCoords</div>
|
<div id="getBoundingClientRectEx" style="background-color:yellow;font-size:14px;border:4px solid black;margin:2px;cursor:pointer">Кликните, чтобы получить координаты getOffsetSum и getCoords</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="getBoundingClientRectExRes">
|
<div id="getBoundingClientRectExRes">
|
||||||
|
|
|
@ -36,4 +36,3 @@
|
||||||
<li>Напишите код, который получит второй `LI`. Будет ли ваш код работать в IE8-, если комментарий переместить *между* элементами `LI`?</li>
|
<li>Напишите код, который получит второй `LI`. Будет ли ваш код работать в IE8-, если комментарий переместить *между* элементами `LI`?</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
[edit src="solution" task/]
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
Объектом какого класса является `document`, можно выяснить так:
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
alert(document); // [object HTMLDocument]
|
||||||
|
```
|
||||||
|
|
||||||
|
Или так:
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
alert(document.constructor); // function HTMLDocument() { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
Итак, `document` -- объект класса `HTMLDocument`.
|
||||||
|
|
||||||
|
Какое место `HTMLDocument` занимает в иерархии?
|
||||||
|
|
||||||
|
Можно поискать в документации. Но попробуем выяснить это самостоятельно.
|
||||||
|
|
||||||
|
Вопрос не такой простой и требует хорошего понимания [прототипного наследования](/class-inheritance).
|
||||||
|
|
||||||
|
Вспомним, как оно устроено:
|
||||||
|
<ul>
|
||||||
|
<li>Методы объекта `document` находятся в `prototype` конструктора, в данном случае -- `HTMLDocument.prototype`.</li>
|
||||||
|
<li>У `HTMLDocument.prototype` есть ссылка `__proto__` на прототип-родитель.</li>
|
||||||
|
<li>У прототипа-родителя может быть ссылка `__proto__` на его родитель, и так далее.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
При поиске свойства в `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`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Где в DOM-иерархии document?
|
||||||
|
|
||||||
|
[importance 4]
|
||||||
|
Объектом какого класса является `document`?
|
||||||
|
|
||||||
|
Какое место он занимает в DOM-иерархии?
|
||||||
|
|
||||||
|
Наследует ли он `Node` или `Element`?
|
||||||
|
|
||||||
|
Воспользуйтесь для решения тем фактом, что DOM-узлы образуют стандартную прототипную иерархию классов.
|
||||||
|
|
|
@ -38,35 +38,57 @@
|
||||||
alert( document.body ); // [object HTMLBodyElement]
|
alert( document.body ); // [object HTMLBodyElement]
|
||||||
```
|
```
|
||||||
|
|
||||||
Детальное описание свойств и методов каждого DOM-класса дано в [спецификации](http://www.whatwg.org/specs/web-apps/current-work/multipage/).
|
Можно и проверить при помощи `instanceof`:
|
||||||
|
|
||||||
Например, [The input element](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element) описывает класс, соответствующий `<input>`, включая [interface HTMLInputElement](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#htmlinputelement), который нас как раз и интересует.
|
|
||||||
|
|
||||||
Вот из него выдержка:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
//+ 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)` различен.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>`console.log` выводит элемент в виде, удобном для исследования HTML-структуры.</li>
|
||||||
|
<li>`console.dir` выводит элемент в виде JavaScript-объекта, удобно для анализа его свойств.</li>
|
||||||
|
</ul>
|
||||||
|
Попробуйте сами на `document.body`.
|
||||||
|
[/smart]
|
||||||
|
|
||||||
|
Детальное описание свойств и методов каждого DOM-класса дано в [спецификации](https://html.spec.whatwg.org/multipage/).
|
||||||
|
|
||||||
|
Например, [The input element](https://html.spec.whatwg.org/multipage/forms.html#the-input-element) описывает класс, соответствующий `<input>`, включая [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 {
|
interface HTMLInputElement: HTMLElement {
|
||||||
|
|
||||||
|
// у всех таких элементов есть строковые свойства
|
||||||
|
// accept, alt, autocomplete, value
|
||||||
attribute DOMString accept;
|
attribute DOMString accept;
|
||||||
attribute DOMString alt;
|
attribute DOMString alt;
|
||||||
attribute DOMString autocomplete;
|
attribute DOMString autocomplete;
|
||||||
|
attribute DOMString value;
|
||||||
|
|
||||||
|
// и логическое свойство autofocus
|
||||||
attribute boolean autofocus;
|
attribute boolean autofocus;
|
||||||
...
|
...
|
||||||
attribute DOMString value;
|
// а также метод select, который значение не возвращает (void)
|
||||||
...
|
|
||||||
void select();
|
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), который достаточно легко понять "с ходу".
|
|
||||||
|
|
||||||
В частности, выше мы видим, что:
|
|
||||||
<ul>
|
|
||||||
<li>`HTMLInputElement` наследует от `HTMLEmenet`.</li>
|
|
||||||
<li>У всех `<input>`-элементов есть свойства `accept`, `alt`, `autocomplete` и `value`, которые являются строками (`DOMString`), а также также свойство `autofocus` с логическим значением.</li>
|
|
||||||
<li>Также есть метод `select()`, который значение не возвращает (`void`).</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Далее в этом разделе мы поговорим о самых главных свойствах узлов DOM, которые используются наиболее часто.
|
Далее в этом разделе мы поговорим о самых главных свойствах узлов DOM, которые используются наиболее часто.
|
||||||
|
|
||||||
## Тип: nodeType
|
## Тип: nodeType
|
||||||
|
@ -83,7 +105,7 @@ interface HTMLInputElement: HTMLElement {
|
||||||
|
|
||||||
```js
|
```js
|
||||||
interface Node {
|
interface Node {
|
||||||
// NodeType
|
// Всевозможные значения nodeType
|
||||||
const unsigned short ELEMENT_NODE = 1;
|
const unsigned short ELEMENT_NODE = 1;
|
||||||
const unsigned short ATTRIBUTE_NODE = 2;
|
const unsigned short ATTRIBUTE_NODE = 2;
|
||||||
const unsigned short TEXT_NODE = 3;
|
const unsigned short TEXT_NODE = 3;
|
||||||
|
@ -447,9 +469,9 @@ chatDiv.innerHTML += "Как дела?";
|
||||||
|
|
||||||
Как правило, видим или невидим узел, определяется через CSS, свойствами `display` или `visibility`.
|
Как правило, видим или невидим узел, определяется через CSS, свойствами `display` или `visibility`.
|
||||||
|
|
||||||
В стандарте HTML5 предусмотрен специальный атрибут (он же свойство) для этого: `hidden`.
|
В стандарте HTML5 предусмотрен специальный атрибут и свойство для этого: `hidden`.
|
||||||
|
|
||||||
Его поддерживают все современные браузеры, кроме старых IE.
|
Его поддерживают все современные браузеры, кроме IE10-.
|
||||||
|
|
||||||
В примере ниже второй и третий `<div>` скрыты:
|
В примере ниже второй и третий `<div>` скрыты:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Порядок обработки событий
|
# Порядок обработки событий
|
||||||
|
|
||||||
События могут возникать не только по очереди, но и "пачкой" по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для `onclick` -- посетитель провёл мышкой, а это уже `mousemove`.
|
События могут возникать не только по очереди, но и "пачкой" по много сразу. Возможно и такое, что во время обработки одного события возникают другие, например пока выполнялся код для `onclick` -- посетитель нажал кнопку на клавиатуре (событие `keydown`).
|
||||||
|
|
||||||
Здесь мы разберём, как браузер обычно работает с одновременно возникающими событиями и какие есть исключения из общего правила.
|
Здесь мы разберём, как браузер обычно работает с одновременно возникающими событиями и какие есть исключения из общего правила.
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@
|
||||||
В действии:
|
В действии:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!--+ autorun no-beautify -->
|
<!--+ autorun height=150 no-beautify -->
|
||||||
<textarea rows="6" cols="40" id="area">Кликни меня
|
<textarea rows="8" cols="40" id="area">Кликни меня
|
||||||
</textarea>
|
</textarea>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
Когда посетитель фокусируется на элементе, возникает событие `onfocus`. Обычно оно происходит, когда посетитель кликает на поле ввода, например:
|
Когда посетитель фокусируется на элементе, возникает событие `onfocus`. Обычно оно происходит, когда посетитель кликает на поле ввода, например:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!--+ run autorun -->
|
<!--+ run height=80 autorun -->
|
||||||
<p>При фокусе на поле оно изменит значение.</p>
|
<p>При фокусе на поле оно изменит значение.</p>
|
||||||
<input type="text" onfocus="this.value = 'Фокус!'" value="Кликни меня">
|
<input type="text" onfocus="this.value = 'Фокус!'" value="Кликни меня">
|
||||||
```
|
```
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
При этом обработчик `onclick` вызовет метод `focus()` на текстовом поле `text`. Код обработчика `onfocus`, который при этом запустится, сработает синхронно, прямо сейчас, до завершения `onclick`.
|
При этом обработчик `onclick` вызовет метод `focus()` на текстовом поле `text`. Код обработчика `onfocus`, который при этом запустится, сработает синхронно, прямо сейчас, до завершения `onclick`.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!--+ autorun no-beautify -->
|
<!--+ autorun height=80 no-beautify -->
|
||||||
<input type="button" id="button" value="Нажми меня">
|
<input type="button" id="button" value="Нажми меня">
|
||||||
<input type="text" id="text" size="60">
|
<input type="text" id="text" size="60">
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@
|
||||||
Если это неудобно, можно запланировать `text.focus()` чуть позже через `setTimeout(..., 0)`, вот так
|
Если это неудобно, можно запланировать `text.focus()` чуть позже через `setTimeout(..., 0)`, вот так
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!--+ autorun -->
|
<!--+ autorun height=80 -->
|
||||||
<input type="button" id="button" value="Нажми меня">
|
<input type="button" id="button" value="Нажми меня">
|
||||||
<input type="text" id="text" size="60">
|
<input type="text" id="text" size="60">
|
||||||
|
|
||||||
|
|
|
@ -65,12 +65,14 @@ ball.onmousedown = function(e) { // 1. отследить нажатие*!*
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Если запустить этот код на картинке `#ball`, то мы заметим нечто странное. При начале переноса мяч "раздваивается" и переносится не сам мяч, а его "клон".
|
Если запустить этот код, то мы заметим нечто странное. При начале переноса мяч "раздваивается" и переносится не сам мяч, а его "клон".
|
||||||
|
|
||||||
[online]
|
[online]
|
||||||
В действии (внутри ифрейма):
|
Это можно увидеть в действии внутри ифрейма:
|
||||||
|
|
||||||
[iframe src="ball" height=230]
|
[iframe src="ball" height=230]
|
||||||
|
|
||||||
|
Попробуйте перенести мяч мышкой и вы увидите описанное, довольно-таки странное, поведение.
|
||||||
[/online]
|
[/online]
|
||||||
|
|
||||||
Это потому, что браузер имеет свой собственный Drag'n'Drop, который автоматически запускается и вступает в конфликт с нашим. Это происходит именно для картинок и некоторых других элементов.
|
Это потому, что браузер имеет свой собственный Drag'n'Drop, который автоматически запускается и вступает в конфликт с нашим. Это происходит именно для картинок и некоторых других элементов.
|
||||||
|
|
|
@ -9,26 +9,25 @@
|
||||||
|
|
||||||
<p>Страница создаёт объект <code>XMLHttpRequest</code> каждые 50мс.</p>
|
<p>Страница создаёт объект <code>XMLHttpRequest</code> каждые 50мс.</p>
|
||||||
|
|
||||||
<p>Смотрите на память, она течёт в IE<9.</p>
|
<p>Нажмите на кнопку и смотрите на память, она течёт в IE<9.</p>
|
||||||
|
|
||||||
|
<button onclick="setInterval(leak, 50);">Запустить</button>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function leak() {
|
function leak() {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
xhr.open('GET', 'something.js?' + Math.random(), true);
|
xhr.open('GET', '?' + Math.random(), true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||||
document.getElementById('test').innerHTML++
|
document.getElementById('test').innerHTML++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
onload = function() {
|
|
||||||
setInterval(leak, 50);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>Количество запросов: <span id="test">0</span></div>
|
<div>Количество запросов: <span id="test">0</span></div>
|
||||||
|
|
BIN
figures.sketch
BIN
figures.sketch
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue