Можно ли провести различие между не захватывающей функцией и замыканием в Javascript?
Два функциональных объекта:
// toplevel
var f1 = function(){return k;};
var f2 = (function(k){return function(){return k;}})(42);
имеют такой же исходный код "function(){return k;}", но f1
это функция, где k
ищется в глобальной среде, f2
вместо этого закрытие, которое захватило местный k
,
Можно ли сказать f2
такое закрытие? typeof
для обоих "function"
и не помогает...
Например, сохранение исходного кода функции в базе данных может иметь смысл, так как вы можете перестроить функцию с помощью eval
, Хранение исходного кода замыкания вместо этого не будет работать из-за захваченных переменных.
3 ответа
Закрытия не являются типами. Закрытие - это то, что позволяет функции обращаться к переменным в своей области, даже после того, как эта область должна быть удалена. Посмотрите, что он заказывает книгу "Не знаю", чтобы получить более подробное описание.
Второе, что вы помещаете, - это немедленно вызываемая функция. () Вокруг функции делает ее выражением. Он оценивается и возвращается, а затем немедленно вызывается.
Происходит то, что f1 определяется в области видимости верхнего уровня, но f2 определяется во внутренней области действия немедленно вызываемой функции, а затем возвращается на верхний уровень. Закрытие - это то, что позволяет f2 получить доступ к k после того, как его заданная область должна быть уничтожена. Можно сказать, что f2 замыкается на k.
Короче говоря, нет никакой возможности определить, в какой области была создана функция.
Как сказал ncphillips, Closure не является типом js. Это структура данных для решения проблемы динамического объема. Вы можете взглянуть по этой ссылке: https://en.wikipedia.org/wiki/Scope_(computer_science) В большинстве функциональных языков программирования замыкание является прозрачным для разработчика, нет способа посетить или контролировать эту структуру. Каждый раз, когда vm создает замыкание (обычно это происходит, когда вы объявляете функцию), он просматривает цепочку областей действия и "делает ссылку на них (это мое слово, может быть, не очень понятно)". В вашем коде:
var f1 = function(){return k;};
var f2 = (function(k){return function(){return k;}})(42);
Вы можете видеть, что функция, на которую ссылается f1, и функция, на которую ссылается f2, имеют разную цепочку областей видимости, хотя оба возвращают k, но то, на что ссылается k, не является одной и той же областью. Это не значит, что если f2 или f1 - замыкание, они оба являются функцией, у них обоих есть замыкание, но в этом примере они не ссылаются на одно и то же замыкание.
Они оба возвращают k, когда они это делают, они заглянут внутрь своего замыкания (более или менее равного их цепочке областей видимости), чтобы найти "k". Для f1 вы не указали ему "k" в этом коде, поэтому он продолжает искать, пока не станет глобальным, если по-прежнему нет "k", а затем вернуть undefined. Для f2, область в function(k){}
является 'самой низкой областью' для f2, и он нашел 'k', поэтому верните его. Это разница.
Ключевым словом создания замыкания является объявление функции, когда vm объявляет функцию, оно дает закрытие функции, полагаясь на область действия объявления.
Мой английский не очень хорош, просто надеюсь, что это поможет вам.
Если вы посмотрите в отладчике Chrome на f1/f2.prototype, вы получите расширяемый объект {}. Внутри у вас есть конструктор, который также расширяется. Как только вы расширите это, внутри вы можете увидеть <function scope>
элемент, который содержит k и его значение.
Согласно стандарту ECMA, объем закрытия недоступен программно.
При этом я написал доказательство концептуального кода, который может определить, является ли функция замыканием или нет, с учетом ваших примерных функций. Различные типы замыкания требуют более сложных механизмов, но это может сработать:
var k=10;
var f1 = function(){return k;};
var f2 = (function(k){return function(){return k;}})(42);
function isClosure(f) {
var testF=new Function('return ('+f.toString()+')();');
return testF()!=f();
}
alert('f1 is '+(isClosure(f1)?'':'not')+' a closure\r\nf2 is '+(isClosure(f2)?'':'not')+' a closure');