2013-07-08 10 views
0

Рассмотрим следующий код:Javascript функция внутреннего сфера

function nepaliBuddha() { 
    var a = 20; 

    return function buddhaNepal() { 
     console.log(a); 
    } 
} 

var closure = nepaliBuddha(); 

closure(); // logs 20 
  1. Теперь, когда мы вызываем closure выход 20. Это доказывает, что внутреннее свойство области ([[scope]]) было присвоено внутренней функции, где оно было определено или указано при объявлении. Если это не было назначено при объявлении, не было способа регистрировать 20, поскольку он вызывается в другом контексте

  2. Вызов closure() цепочка областей действия контекста создается при вызове функции и состоит из объекта активации или VO текущего контекста и внутреннего свойства [[scope]] этой функции.

  3. Invocation также создает свойство [[scope]], это означает, что свойство внутренней видимости создается при объявлении, а также при выполнении, не так ли?

  4. Обычно определение говорит о том, что свойство [[scope]] создается во время выполнения или при вызове функции, но это не так, поскольку свойство [[scope]] уже назначено также в объявлении.

  5. Я думаю, что свойство [[scope]] может обновиться после выполнения функции, не так ли? Пожалуйста, дайте четкое определение внутренней собственности [[scope]]. Как и когда он создается во время объявления или во время выполнения или в оба раза.

+1

Я не считаю, что замыкание создается дважды. Я думаю, по определению, это не будет сбор мусора, пока функция, которая ссылается на нее, также выходит за рамки. Если вы спрашиваете, будет ли второй вызов NephaliBuddha создать другой объект, тогда да, это будет. Он не зависит от того, который был создан ранее. – Hath995

+1

Возможный дубликат [Как работают блокировки JavaScript?] (Http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Paul

+0

связанный с этим вопрос закрывается, я спрашиваю о внутренней области собственность не о закрытии –

ответ

7

Вау, разве вы не совсем смущены. Хорошо, я постараюсь объяснить закрытие как можно проще.

Во-первых, мы начнем с областей. Есть два типа областей:

  1. Блок прицелы
  2. Функция прицелы

Блок Объем начинается сразу же, когда это происходит в программе. С другой стороны, область действия не начинается до тех пор, пока не будет вызвана функция. Следовательно, несколько вызовов одной и той же функции приводят к созданию нескольких областей.

У JavaScript нет блоков. Он имеет только области функций. Следовательно, чтобы эмулировать область блока, нам нужно создать выражение функции и немедленно выполнить его. Это patttern называется immediately invoked function expression (IIFE) и это выглядит следующим образом:

(function() { 
    // this is the JS equivalent of a block scope 
}()); 

Помимо блока областей и функции прицелы есть другой способ классификации областей. Поэтому мы также имеем:

  1. лексических прицелы
  2. Dynamic прицелы

Это различие касается только потому, что работать области блока прицелы всегда лексическая области видимости. JavaScript имеет только лексические области.

Чтобы понять разницу между лексическими областями и динамическими областями, нам нужно понять разницу между свободными и связанными переменными.

  1. Свободная переменная - это переменная, которая используется внутри функции, но не объявляется внутри этой функции.
  2. Переменная, объявленная внутри функции, называется связанной с этой функцией.

Рассмотрим следующую программу:

function add(x, y) { 
    return x + y; // x and y are bound to add 
} 

В приведенной выше программе переменные x и y связаны с функцией добавления, поскольку они объявлены в add.

С другой стороны, переменные x и y в следующей программе свободны в функции add, потому что они не объявлены в add, но они используются в add:

function add() { 
    return x + y; // x and y are free within add 
} 

Теперь свободные переменные являются проблемой , Они должны быть сопоставлены с некоторой ценностью, но какая ценность? Именно здесь появляются лексические и динамические области. Я не буду вдаваться в детали, но вы можете read about it on Wikipedia.

Области очень похожи на прототипное наследование. Когда начинается новая область, она наследует от родительской области, формируя цепочку областей, подобных целям прототипов в JavaScript.

Лексические области и динамические области различаются относительно того, к какой родительской области применяется новая область, наследующая форму.

  1. В лексическом масштабе область видимости новой функции наследуется от области действия этой функции (то есть ее лексической среды).
  2. В динамической области видимости новая область функций наследуется от области, в которой была вызвана эта функция (т. Е. Области вызова).

Поскольку JavaScript имеет только лексическое охват, мы не будем беспокоиться о динамическом охвате. Рассмотрим следующую программу:

var count = 0; 

function incrementCount() { 
    return ++count; 
} 

(function() { 
    var count = 100; 
    alert(incrementCount()); // 1 
}()); 

Здесь функция incrementCounter имеет одну свободную переменную - count. Поскольку JavaScript имеет лексическое охват count будет отображаться в глобальную переменную count вместо локального count, объявленного в рамках IIFE. Следовательно, incrementCount возвращает 1, а не 101.

Теперь закрытие работает только на языках, которые имеют лексическое охват.Рассмотрим следующую программу:

function getCounter() { 
    var count = 0; 

    return function() { 
     return ++count; 
    }; 
} 

var counter = getCounter(); 

alert(counter()); // 1 
alert(counter()); // 2 
alert(counter()); // 3 

В приведенной выше программе функция, возвращаемая getCounter является замкнутость относительно переменной count, потому что:

  1. Переменная count свободна в возвращаемой функции (т.е. counter).
  2. Функция перемещается за пределы области действия, в которой объявляется count.

Оба эти условия необходимы для того, чтобы функция называлась замыканием. Для получения дополнительной информации прочитайте следующий ответ: https://stackoverflow.com/a/12931785/783743

Теперь важно понять, что функция counter по-прежнему будет называться закрытием, даже если она никогда не будет вызываться. Закрытие - это просто функция, которая закрывает над переменную (которая называется upvalue закрытия).

Когда мы вызываем getCounter мы создаем новую область (назовем это сфера A), и каждый раз, когда мы вызываем функцию, возвращенное getCounter (т.е. counter) мы создаем новую область, которая наследуется от объема A. Это все. Никакого нового закрытия не создается.

+0

Позвольте мне спросить у одного, когда мы объявим какую-либо функцию, будет ли она сразу назначена внутренняя область видимости? Если да, то свойство внутренней видимости также присваивается во время выполнения или когда вы вызываете функцию. Мой вопрос был два раза: свойство внутренней области beign created.So, что я должен теперь сказать о своих stds, когда будет создано свойство внутренней видимости? –

+0

Нет. Когда вы определяете функцию, JavaScript создает внутреннее свойство, называемое '[[scope]]' для функции, которая содержит лексическую область __, которой принадлежит функция. Например, когда я создаю функцию в глобальной области видимости, свойство '[[scope]]' этой функции будет установлено в глобальную область. Когда я вызываю функцию, JavaScript создает новую область (объект активации), которая наследует от того, что указывает свойство '[[scope]]' этой функции. Свойство '[[scope]]' не изменяется при вызове функции. Он просто используется для определения того, какая область наследуется от –

+0

@Maizere. Прочитайте приведенный выше комментарий. Теперь подумайте об этом логично. Когда вы вызываете функцию, вы создаете новую область. Эта область должна наследоваться из другой области, но какой?Нам нужно хранить лексическую область функции где-то так, чтобы при вызове функции мы могли правильно настроить цепочку областей видимости новой области. Лексическая область каждой функции хранится в ее внутреннем свойстве '[[scope]]'. Он устанавливается только один раз (во время создания функции) и никогда не изменялся. Это только для чтения. Если бы JavaScript имел динамическое масштабирование, тогда не было бы необходимости в свойстве '[[scope]]'. =) –

1

A closure - особый вид объекта, который объединяет две вещи: функцию и среду, в которой была создана эта функция. Среда состоит из любых локальных переменных, которые были в области в то время, когда было закрыто .

function makeFunc() { 
    var name = "Mozilla"; 
    function displayName() { 
     alert(name); 
    } 
    return displayName; 
} 

Позовите makeFunc()

var myFunc = makeFunc(); 
myFunc(); 

В этом случае myFunc является замыкание, которое включает как displayName функцию и «Mozilla» строка, которая существовала, когда крышка была создана, MDN.

Итак, scope создан именно тогда, когда я назвал var myFunc = makeFunc(); и myFunc() (результат makeFunc() вызова) теперь замыкание. Итак, переходим к первой строке, где

closure представляет собой особый вид объекта, который сочетает в себе две вещи: функция, и среда, в которой была создана эта функция.

Теперь рассмотрим эти

function nepaliBuddha() { 
    var a = 1; 
    return function buddhaNepal() { 
     a = a+1; 
     console.log(a); 
    } 
} 
var closure1 = nepaliBuddha(); // An individual scope 
var closure2 = nepaliBuddha(); // An individual scope 

closure1(); // 1 
closure1(); // 2 

closure2(); // 1 
closure2(); // 2 
closure2(); // 3 

Demo.

Это означает, closure1() и closure2() являются затворы и оба имеют свои личные рамки/окружающей среды, и они имеют доступ к своей собственной области, как только они получают его (в этом случае каждый раз, когда вы вызываете nepaliBuddha, вы создаете закрытие и даете/сохраняете его переменной).

Область определяет область, в которой имеются функции, переменные и т. Д. Итак, когда вы определили/объявили функцию buddhaNepal (внутренняя функция) внутри nepaliBuddha (внешняя функция), buddhaNepal (внутренняя функция) была просто отделена от глобальной области и ничего больше. Он не может получить доступ к чему-либо в глобальном масштабе, но у него есть собственный охват, вот и все. nepaliBuddha (внешняя функция) является границей функции buddhaNepal (внутренняя функция), и в этом случае локальная область/окружение внешней функции nepaliBuddha является глобальной областью для buddhaNepal (внутренняя функция).

в JavaScript, это называется Lexical Scopeing, где определяется, как имена переменных разрешаются вложенных функциях. Другие названия Lexical Scope - это статическое охват или закрытие. Это означает, что область внутренней функции содержит область родительской функции.

+0

Нет ничего особенного в закрытии. Это похоже на любую другую функцию JavaScript. Однако замыкания более интересны, чем другие функции, потому что закрытие сохраняет свои значения даже после того, как они выходят за рамки. Раньше я думал, что закрытие было особенным и что они были обработаны иначе, чем другие функции. Однако это не так - интерпретатор JavaScript обрабатывает каждую функцию таким же образом. Для получения дополнительной информации прочитайте следующий комментарий: http://stackoverflow.com/questions/12930272/javascript-closures-vs-anonymous-functions/12931785#comment17582302_12931785 –

+0

@AaditMShah, да, это именно так, '' закрытие' просто функция, но вы живете в разных масштабах. –

Смежные вопросы