Объем
Область - это область функции переменной и функции. Все переменные, объявленные в функции в JavaScript, всегда видны в организме функции. В JavaScript существуют глобальные прицелы и локальные прицелы, но нет никаких областей на уровне блока. Приоритет локальных переменных выше, чем у глобальных переменных. Через несколько примеров мы можем понять «невысказанные правила» масштаба в JavaScript (это также вопросы, которые часто задают в интервью).
1. Заранее
Пример 1:
var scope = "global"; function scopetest () {console.log (scope); var scope = "local"} scopetest (); //неопределенныйВывод здесь не определен, и ошибки нет. Это связано с тем, что объявления в функции, о которой мы упомянули выше, всегда видны в теле функции. Вышеуказанная функция эквивалентна:
var scope = "global"; function scopetest () {var scope; console.log (Scope); scope = "local"} scopetest (); //местныйОбратите внимание, что если var забыта, переменная объявляется как глобальная переменная.
2. Без применения на уровне блоков
В отличие от других языков, которые мы используем обычно, в JavaScript нет области на уровне блока:
function scopetest () {var scope = {}; if (actanceOf object) {var j = 1; for (var i = 0; i <10; i ++) {//console.log(i); } console.log (i); // Выход 10} console.log (j); // Выход 1}В JavaScript объем функции переменных является уровнем функции, то есть все переменные в функции определяются во всей функции, которая также приносит некоторые «невысказанные правила», с которыми мы столкнемся, если мы не будем осторожны:
var scope = "hello"; function scopetest () {console.log (scope); // ① var scope = "no"; console.log (scope); // ②}Выход значения в ① был фактически неопределенным, что безумие. Мы определили значение глобальной переменной. Разве это место не должно быть привет? Фактически, приведенный выше код эквивалентен:
var scope = "hello"; function scopetest () {var scope; console.log (scope); // ① scope = "нет"; console.log (scope); // ②}Объявление ранних и глобальных переменных имеет более низкий приоритет, чем локальные переменные. Согласно этим двум правилам, нетрудно понять, почему выход не определен.
Цепочка применения
В JavaScript каждая функция имеет свой собственный контекст выполнения. Когда код будет выполнен в этой среде, будет создана цепочка объектов переменных. Цепочка областей - это список объектов или цепочка объекта, которая обеспечивает упорядоченный доступ к переменным объектам.
Передний конец цепочки объема является переменным объектом текущей среды выполнения кода, которая часто называется «активным объектом». Поиск переменных начинается с объекта первой цепи. Если объект содержит атрибуты переменной, то поиск будет остановлен. Если нет, то поиск будет продолжать искать верхнюю цепочку областей, пока не будет найден глобальный объект:
Поиск цепочек объемов шаг за шагом также повлияет на производительность программы. Чем дольше цепочка переменных, тем больше влияние на производительность. Это также главная причина, по которой мы стараемся избегать использования глобальных переменных.
Закрытие
Основные понятия
Область - это предпосылка для понимания закрытия. Закрытие относится к возможности доступа к переменным во внешней области в текущей области.
function createClosure () {var name = "jack"; return {setStr: function () {name = "rose"; }, getStr: function () {return name + ": hello"; }}} var builder = new CreateClosure (); Builder.setStr (); console.log (builder.getstr ()); // Роза: ПриветПриведенный выше пример возвращает два закрытия в функции, оба из которых сохраняют ссылки на внешнюю область, поэтому переменные во внешней функции всегда доступны, где они называются. Функции, определенные внутри функции, добавят активный объект внешней функции в свою собственную цепочку области. Следовательно, в приведенном выше примере внутренняя функция может получить доступ к свойствам внешней функции через внутреннюю функцию. Это также способ JavaScript имитировать личные переменные.
ПРИМЕЧАНИЕ. Поскольку закрытие будет иметь дополнительные прицелы функций (внутренние анонимные функции несут прицелы внешних функций), закрытие будет занимать больше пространства памяти, чем другие функции, а чрезмерное использование может привести к увеличению использования памяти.
Переменные в закрытии
При использовании закрытия, из -за влияния механизма цепочки объема, закрытие может получить только последнее значение внутренней функции. Одним из побочных эффектов является то, что если внутренняя функция находится в цикле, значение переменной всегда является последним значением.
// Этот экземпляр не является разумным и имеет определенные факторы задержки. Это в основном для иллюстрации задач в функции цикла закрытия timemanage () {for (var i = 0; i <5; i ++) {settimeout (function () {console.log (i);}, 1000)}; }Вышеуказанная программа не вводит числа 1-5, как мы и ожидали, но выводит 5 все 5 раз. Давайте посмотрим на другой пример:
function createClosure () {var result = []; for (var i = 0; i <5; i ++) {result [i] = function () {return i; }} return result;}Вызов CreateClostust () [0] () возвращает 5, а CreateClosure () [4] () Возвращает значение по -прежнему 5. Когда внешняя функция возвращается, значение I в настоящее время составляет 5, поэтому значение каждой внутренней функции I также составляет 5.
Так как решить эту проблему? Мы можем вызвать возврат ожидаемого результата через анонимную обертку (экспрессия анонимной самообучения функции):
function timemanage () {for (var i = 0; i <5; i ++) {(function (num) {settimeout (function () {console.log (num);}, 1000);}) (i); }}Или вернуть назначение анонимной функции в анонимной функции закрытия:
function timemanage () {for (var i = 0; i <10; i ++) {settimeout ((function (e) {return function () {console.log (e);}}) (i), 1000)}} // timemanager (); Выход 1,2,3,4,5function createClosure () {var result = []; for (var i = 0; i <5; i ++) {result [i] = function (num) {return function () {console.log (num); }} (i); } return result;} // createClosure () [1] () Выход 1; CreateClosture () [2] () Выход 2Будь то анонимная обертка или вложенные анонимные функции, в принципе, поскольку функция передается по значению, значение переменной, которую я будет скопирована в фактическое число параметров, а анонимная функция создается внутри анонимной функции, чтобы вернуть NUM, так что каждая функция имеет копию NUM, которая не будет влиять на друг друга.
Это в закрытии
Обратите особое внимание при использовании этого при закрытии, так как небольшая небрежность может вызвать проблемы. Обычно мы понимаем, что этот объект связан функцией во время выполнения. В глобальной функции этот объект представляет собой окно -объект. Когда функция называется методом в объекте, это равно этому объекту (TODO делает процесс сортировки по этому поводу). Поскольку объем анонимных функций является глобальным, это закрытие обычно указывает на окно глобального объекта:
var scope = "global"; var object = {scope: "local", getscope: function () {return function () {return this.scope; }}}Calling object.getScope () () возвращает значение Global, а не локальное, которое мы ожидали. Ранее мы говорили, что внутренние анонимные функции в закрытии будут нести область внешней функции, так почему бы не получить ее от внешней функции? Когда каждая функция вызвана, это и аргументы будут созданы автоматически. При поиске внутренних анонимных функций они ищут переменные, которые мы хотим в активном объекте. Следовательно, прекратите поиск внешних функций, и никогда невозможно напрямую получать непосредственные доступа к переменным во внешних функциях. Короче говоря, когда функция называется методом объекта в закрытии, важно уделять особое внимание, что это в анонимной функции в рамках метода указывает на глобальную переменную.
К счастью, мы можем решить эту проблему очень просто, просто сохранить ее в сфере внешней функции в переменной, к которой можно получить доступ к закрытию:
var scope = "global"; var object = {scope: "local", getscope: function () {var that = this; return function () {return that.scope; }}} object.getScope () () () возвращает значение локально.Память и производительность
Поскольку закрытие содержит такую же ссылку на цепочку объемов, что и контекст времени выполнения функции, оно будет иметь определенный негативный эффект. Когда активный объект и контекст времени выполнения в функции разрушаются, активный объект не может быть уничтожен, поскольку все еще существует ссылка на активный объект, что означает, что закрытие занимает больше пространства памяти, чем обычные функции, а также может вызвать утечку памяти в браузере IE, следующим образом:
function bindevent () {var target = document.getelementbyid ("elem"); target.onclick = function () {console.log (target.name); }}В приведенном выше примере анонимная функция генерирует ссылку на цель внешнего объекта. До тех пор, пока существует анонимная функция, ссылка не исчезнет, а целевой объект внешней функции не будет разрушен, что создает круглую ссылку. Решение состоит в том, чтобы уменьшить круглые ссылки на внешние переменные, создав копию Target.Name и вручную сбросить объект:
function bindevent () {var target = document.getelementbyid ("elem"); var name = target.name; target.onclick = function () {console.log (name); } target = null; }Если в закрытии есть доступ к внешним переменным, путь поиска для идентификаторов, несомненно, будет добавлен, и при определенных обстоятельствах это также приведет к потере производительности. Мы упомянули ранее: Попробуйте хранить внешние переменные в локальные переменные, чтобы уменьшить длину поиска цепочек объема.
Резюме: Закрытие не уникальна для JavaScript, но у них есть свои уникальные проявления в JavaScript. Используя закрытие, мы можем определить некоторые частные переменные в JavaScript и даже имитировать области на уровне блоков. Однако во время использования закрытия нам также необходимо понять существующие проблемы, чтобы избежать ненужных проблем.