diff --git a/1-js/4-data-structures/12-typeof-duck-typing/article.md b/1-js/4-data-structures/12-typeof-duck-typing/article.md index 733bf476..7815b69c 100644 --- a/1-js/4-data-structures/12-typeof-duck-typing/article.md +++ b/1-js/4-data-structures/12-typeof-duck-typing/article.md @@ -1,4 +1,4 @@ -# Оператор typeof и утиная типизация +# Полиморфизм, typeof и утиная типизация В этой главе мы рассмотрим, как создавать *полиморфные* функции, то есть такие, которые по-разному обрабатывают аргументы, в зависимости от их типа. Например, функция вывода может по-разному форматировать числа и даты. @@ -119,6 +119,23 @@ if (x.getTime) { Но как раз в этом и есть смысл утиной типизации: если объект похож на массив, у него есть методы массива, то будем работать с ним как с массивом (какая разница, что это на самом деле). +[smart header="Метод `Array.isArray()`"] +Для массивов есть специальный метод проверки: `Array.isArray(arr)`, который возвращает `true` только если `arr` -- массив: +```js +//+ run +alert( Array.isArray([1,2,3]) ); // true +alert( Array.isArray("not array")); // false +``` + +Этот метод уникален в своём роде, других аналогичных (типа `Object.isObject`, `Date.isDate`) -- нет. + +Если нужно удостовериться, что мы получили именно массив, а не нечто похожее на него -- можно использовать `Array.isArray`. Но при этом нужно отдавать себе отчёт, что этим мы одновременно ограничиваем применимость кода: "похожие на массив" данные теперь обрабатываться не будут. Решение зависит от конкретной ситуации. +[/smart] + + + + + ## Полиморфизм Пример полиморфной функции -- `sayHi(who)`, которая будет говорить "Привет" своему аргументу, причём если передан массив -- то "Привет" каждому: @@ -127,7 +144,7 @@ if (x.getTime) { //+ run function sayHi(who) { - if (who.forEach) { // проверка на массив (или что-то похожее) + if (Array.isArray(who)) { who.forEach(sayHi); } else { alert( 'Привет, ' + who ); @@ -140,13 +157,16 @@ sayHi("Вася"); // Привет, Вася // Вызов с массивом sayHi(["Саша", "Петя"]); // Привет, Саша... Петя -// Вызов с вложенными массивами +// Вызов с вложенными массивами - тоже работает! sayHi(["Саша", "Петя", ["Маша", "Юля"]]); // Привет Саша..Петя..Маша..Юля ``` -Здесь вместо `splice` проверяется наличие `forEach`. Так надёжнее, поскольку именно его мы собираемся использовать. - -Обратите внимание, получилась даже поддержка вложенных массивов. Да здравствует рекурсия! +Здесь используется не "duck typing", а "жёсткая" проверка на массив. Можно было бы и поступить мягче -- проверить только наличие метода `forEach`: +```js +if (who.forEach) { + ... +} +``` ## Итого diff --git a/1-js/4-data-structures/2-number/article.md b/1-js/4-data-structures/2-number/article.md index 825263f7..b25a936b 100644 --- a/1-js/4-data-structures/2-number/article.md +++ b/1-js/4-data-structures/2-number/article.md @@ -101,16 +101,17 @@ if (NaN === NaN) alert( "===" ); // не сработает ``` -
  • Значение `NaN` можно проверить специальной функцией `isNaN(n)`, которая возвращает `true` если аргумент -- `NaN` и `false` для любого другого значения. +
  • Значение `NaN` можно проверить специальной функцией `isNaN(n)`, которая преобразует аргумент к числу и возвращает `true`, если получилось `NaN`, и `false` -- для любого другого значения. ```js //+ run var n = 0 / 0; alert( isNaN(n) ); // true +alert( isNaN("12") ); // false, строка преобразовалась к обычному числу 12 ``` -[smart] +[smart header="Забавный способ проверки на `NaN`"] Отсюда вытекает забавный способ проверки значения на `NaN`: можно проверить значение на равенство самому себе, если не равно -- то `NaN`: ```js @@ -122,6 +123,7 @@ if (n !== n) alert( 'n = NaN!' ); Это работает, но для наглядности лучше использовать `isNaN(n)`. [/smart] +
  • Значение `NaN` "прилипчиво". Любая операция с `NaN` возвращает `NaN`. diff --git a/7-frames-and-windows/2-iframes/article.md b/7-frames-and-windows/2-iframes/article.md index 744effa2..eed3b041 100644 --- a/7-frames-and-windows/2-iframes/article.md +++ b/7-frames-and-windows/2-iframes/article.md @@ -1,4 +1,4 @@ -# Окно внутри ифрейма +# Общение между окнами и фреймами Элемент `iframe` является обычным узлом DOM, как и любой другой. Существенное отличие -- в том, что с ним связан объект `window` внутреннего окна. Он доступен по ссылке `iframe.contentWindow`.