- •Введение
- •Введение в JavaScript
- •Справочники и спецификации
- •Редакторы для кода
- •Консоль разработчика
- •Основы JavaScript
- •Привет, мир!
- •Внешние скрипты, порядок исполнения
- •Структура кода
- •Современный стандарт, «use strict»
- •Переменные
- •Правильный выбор имени переменной
- •Шесть типов данных, typeof
- •Основные операторы
- •Операторы сравнения и логические значения
- •Побитовые операторы
- •Взаимодействие с пользователем: alert, prompt, confirm
- •Условные операторы: if, '?'
- •Логические операторы
- •Преобразование типов для примитивов
- •Циклы while, for
- •Конструкция switch
- •Функции
- •Функциональные выражения
- •Именованные функциональные выражения
- •Всё вместе: особенности JavaScript
- •Качество кода
- •Отладка в браузере Chrome
- •Советы по стилю кода
- •Как писать неподдерживаемый код?
- •Автоматические тесты при помощи chai и mocha
- •Структуры данных
- •Введение в методы и свойства
- •Числа
- •Строки
- •Объекты как ассоциативные массивы
- •Объекты: перебор свойств
- •Объекты: передача по ссылке
- •Массивы c числовыми индексами
- •Массивы: методы
- •Массив: перебирающие методы
- •Псевдомассив аргументов «arguments»
- •Дата и Время
- •Замыкания, область видимости
- •Глобальный объект
- •Замыкания, функции изнутри
- •[[Scope]] для new Function
- •Локальные переменные для объекта
- •Модули через замыкания
- •Управление памятью в JavaScript
- •Устаревшая конструкция «with»
- •Методы объектов и контекст вызова
- •Методы объектов, this
- •Преобразование объектов: toString и valueOf
- •Создание объектов через «new»
- •Дескрипторы, геттеры и сеттеры свойств
- •Статические и фабричные методы
- •Явное указание this: «call», «apply»
- •Привязка контекста и карринг: «bind»
- •Функции-обёртки, декораторы
- •Некоторые другие возможности
- •Типы данных: [[Class]], instanceof и утки
- •Формат JSON, метод toJSON
- •setTimeout и setInterval
- •Запуск кода из строки: eval
- •Перехват ошибок, «try..catch»
- •ООП в функциональном стиле
- •Введение
- •Внутренний и внешний интерфейс
- •Геттеры и сеттеры
- •Функциональное наследование
- •ООП в прототипном стиле
- •Прототип объекта
- •Свойство F.prototype и создание объектов через new
- •Встроенные «классы» в JavaScript
- •Свои классы на прототипах
- •Наследование классов в JavaScript
- •Проверка класса: «instanceof»
- •Свои ошибки, наследование от Error
Различие в скорости на таком примере может составлять, в зависимости от интерпретатора, 2-10
раз.
Вообще, этот пример — не показателен. Ещё раз обращаю ваше внимание на то, что такие искусственные «микротесты» часто врут. Правильно их делать — отдельная наука, которая выходит за рамки этой главы. Но и на практике ускорение в 2-10 раз оптимизацией по количеству объектв (и вообще, любых значений) — отнюдь не миф, а вполне достижимо.
В реальной жизни в большинстве ситуаций такая оптимизация несущественна, просто потому что «JavaScript и так достаточно быстр». Но она может быть эффективной для «узких мест» кода.
Устаревшая конструкция «with»
Конструкция withпозволяет использовать в качестве области видимости для переменных произвольный объект.
В современном JavaScript от этой конструкции отказались. С use strictона не работает, но её ещё
можно найти в старом коде, так что стоит познакомиться с ней, чтобы если что — понимать, о чём речь.
Синтаксис:
with(obj) {
...код...
}
Любое обращение к переменной внутри withсначала ищет её среди свойств obj, а только потом — вне with.
Пример
В примере ниже переменная будет взята не из глобальной области, а из obj:
var a = 5;
var obj = { a: 10
};
with(obj) {
alert( a ); // 10, из obj
}
Попробуем получить переменную, которой в objнет:
var b = 1;
var obj = { a: 10
};
with(obj) {
alert( b ); // 1, из window
}
Здесь интерпретатор сначала проверяет наличие obj.b, не находит и идет вне with.
Особенно забавно выглядит применение вложенных with:
var obj = { weight: 10, size: {
width: 5, height: 7
}
};
with(obj) {
with(size) { // size будет взят из obj
alert( width * height / weight ); // width,height из size, weight из obj
}
}
Свойства из разных объектов используются как обычные переменные… Магия! Порядок поиска переменных в выделенном коде: size => obj => window.
Изменения переменной
При использовании with, как и во вложенных функциях — переменная изменяется в той области, где была найдена.
Например:
var obj = { a: 10
}
with(obj) { a = 20;
}
alert( obj.a ); // 20, переменная была изменена в объекте
Почему отказались от with?
Есть несколько причин.
1.В современном стандарте JavaScriptотказались от with, потому что конструкция with подвержена ошибкам и непрозрачна.
Проблемы возникают в том случае, когда в with(obj)присваивается переменная, которая по
замыслу должна быть в свойствах obj, но ее там нет.
Например:
var obj = { weight: 10
};
with(obj) {
weight = 20; // (1) size = 35; // (2)
}
alert( obj.size ); alert( window.size );
В строке (2)присваивается свойство, отсутствующее в obj. В результате интерпретатор, не найдя его, создает новую глобальную переменную window.size.
Такие ошибки редки, но очень сложны в отладке, особенно если sizeизменилась не в window, а где-нибудь во внешнем LexicalEnvironment.
2.Еще одна причина — алгоритмы сжатия JavaScript не любят with. Перед выкладкой на сервер
JavaScript сжимают. Для этого есть много инструментов, например Closure Compiler и UglifyJS . Обычно они переименовывают локальные переменные в более короткие имена, но не свойства объектов. С конструкцией withдо запуска кода непонятно — откуда будет взята переменная.
Поэтому выходит, что, на всякий случай (если это свойство), лучше её не переименовывать. Таким образом, качество сжатия кода страдает.
3.Ну и, наконец, производительность — усложнение поиска переменной из-за withвлечет дополнительные накладные расходы.
Современные движки применяют много внутренних оптимизаций, ряд которых не могут быть применены к коду, в котором есть with.
Вот, к примеру, запустите этот код в современном браузере. Производительность функции fast существенно отличается slowс пустым(!) with. И дело тут именно в with, т.к. наличие этой конструкции препятствует оптимизации.
var i = 0;
function fast() { i++;
}
function slow() { with(i) {} i++;
}
var time = performance.now(); while (i < 1000000) fast();
alert( "Без with: " + (performance.now() time) );
var time = performance.now(); i = 0;
while (i < 1000000) slow();
alert( "С with: " + (performance.now() time) );
Замена with
Вместо withрекомендуется использовать временную переменную, например:
/* вместо with(elem.style) {
top = '10px'; left = '20px';
}
*/
var s = elem.style;
s.top = '10px'; s.left = '0';
Это не так элегантно, но убирает лишний уровень вложенности и абсолютно точно понятно, что будет происходить и куда присвоятся свойства.
Итого
●Конструкция with(obj) { ... }использует objкак дополнительную область видимости. Все переменные, к которым идет обращение внутри блока, сначала ищутся в obj.
●Конструкция withустарела и не рекомендуется по ряду причин. Избегайте её.
Задачи
With + функция
важность: 5
Какая из функций будет вызвана?
