(翻译) closures-are-not-complicated

Total : After reading this article needs 20 Fenzhong

 

This article explains some of the content of the closure , the author is to take the ES5 specification in terms of some of the terminology .

And it may be an article on the blog mentioned binding object, (lexical environment, environment   record) are not the same .

The main place to learn , when you declare the function , in fact, there will be a function of the internal [[Scope]] property , refer to the current context of the binding object. So in fact when this function becomes closures ( such as to be mentioned in the text the callback function ), in the absence of garbage collection mechanism is released , this [[Scope]] property points to the context will not be released .

 

 

Remember to look at the article before distinguish prototype chain and the scope chain difference :

Variables are looked up on the scope chain, starting with the current execution context and going up the tree of enclosing execution contexts.

Properties are looked up firstly on the base object, then on that object's [[Prototoype]] chain (i.e. its internal prototype).

 

 

 

Closures are not complicated

 

 

 

(Note: the term will be a little different in different ES specification, the authors here are some of the terms used ES5 specification)

 

Closures seem to frighten people a bit. Partially I suspect this is down to the academic nature of the term "closure". It sounds like something Californians look to achieve, not something to help you write software. (Disclosure: I mostly grew up in San Francisco, so I'm allowed to poke fun at my fellow Californians. Don't Try This At Home.) I suspect it's also because if you don't know the rules for them, they seem mysterious, and the mysterious is often frightening.

Closures looks very scary, I think this is usually because the term sounds too academic sent,

 

First off, what is a closure? I'll leave a thorough definition to my academic betters, but let's put it this way for my fellow plodders and I: A closure is a function with data intrinsically bound to it.

 

First, what is the closure I give a definition of it:? Closure is a function of some data bound

 

 

 

Consider this code:

function updateDisplay(panel, contentId)
{
    var url;

    url = 'getcontent?id=' + contentId;
    jsonRequest(
        url,
        function(resp)
        {
            if (resp.err)
            {
                panel.addClassName('error');
                panel.update(
                    'Error retrieving content ID '
                    + contentId
                    + ' from "'
                    + url
                    + '", error: '
                    + resp.err);
            }
            else
            {
                panel.removeClassName('error');
                panel.update(resp.json.content);
            }
        }
    );
}

This updates a panel element based on the results of a call to retrieve some JSON data. The call to the jsonRequest function accepts two parameters: The URL that will return the JSON data, and a callback function to trigger when the request completes (one way or the other). If the data was returned successfully, the callback sets the content of the panel from the JSON data and makes sure that the "error" CSS class is not set on the element; if there's an error, it shows details about the error and sets the "error" CSS class. (In this example, we happen to be using Prototype to extend our panel element with the nifty class name and update methods, but that's as much to keep the example simple as anything else.)

The above code is updated according to the obtained panel element JSON data results.

Call jsonRequest accepts two parameters, one is the URL address, there is a callback function, if the data is successfully returned, JSON content will get the callback function is set to panel and ensure that the 'error' is not an element of css class If the returned error, an error is displayed, and opposite to the element 'err'r class.

 

 

The callback above is an example of a closure: A function with data bound to it, in this case the panel and contentId arguments we passed into the updateDisplay function, and also updateDisplay's url local variable. It's useful to have this information bound to the callback, because the jsonRequest function doesn't know anything about panel or contentId, it just knows about triggering the callback — but the callback has the information it needs to do its job.

The above callback function is a closure: a data binding function

updateDisplay this function and introduced to the panel contentId.

jsonRequest function does not know what the panel and contentId is that it only knew trigger callback - callback contains some data

 

 

 

Magic? Nah. I can't speak for closures in other languages, but there's nothing complicated about closures in JavaScript. Seriously. They're dead easy. You need to know, say, three things and you're good to go. Well, four things, but that's only because someone has been misinforming you. Here's a quick list of those four things, after which we'll delve in a bit deeper, and then I'll tell you something at the end that will surprise you for three seconds before you go "Oh, of course":

 

So Js closures is not complex, but also no magic, let's take a more in-depth explain:

 

 

  1. In JavaScript, everything is a data structure, even functions, and — critically — even the context in which functions run. One aspect of that context is a "call object" (that's Flanagan's term, the ECMA specification uses "activation object" — I'll use "call object" because I'm lazy and it's less typing I find it clearer).

      Js everything in the data structure, but also a function, function execution context also, we call context for the "call object" (ECMA standard is called "activation object" but I do think more clearly)

 

  1. JavaScript variable names are resolved on the basis of a "scope chain", which includes (among other things) the global object and all of the current call objects in scope.

Js variable name resolution process is the "scope chain" such a thing, including the current scope of the call object and global object

  1. Functions in JavaScript are lexically scoped — for the plodders like me out there, that means that the things a function can access (the things "in scope" for it) are determined by the context in which the function is defined, not the context in which it's executed.

JS functions are lexical scope, meaning that a function can access something that is determined by the context in which the function declaration, and the context when the decision is not executed

  1. Closures do not create memory leaks. Someone probably told you that they did at some point (perhaps they thought that's what Microsoft was trying to say here).

Closures will not cause a memory leak

Okay, let's see how those things come together to make closures easy.

 

 

 

#1: Everything is a object

When we call a JavaScript function, the context of that call to the function — the parameters we've used, the variables within the function itself — are part of an object called the call object (or, again, "activation object" in ECMA parlance). The interpreter creates a call object for this particular execution of the function and sets some properties on that call object before passing it into the function's code. The properties are:

When we call a js function of time will create a call object, there are some properties

 

  1. A property called arguments which is an array (of sorts, in most implementations it's not actually an Array object) of the actual arguments we called the function with, plus a callee property which is a reference to the function being called.

Called arguments array (.. Most implementations actually not an array object

A callee property points to the called function itself

 

 

  1. A property for each of the arguments defined by the function declaration. The values of these properties are set to the values passed into the function. If any arguments weren't specified (because JavaScript lets you call functions with however many arguments you want, regardless of the definition), properties for any missing arguments are still created on the call object — with the value undefined.

The parameters are

  

  1. A property for every declared variable within the function (e.g., every "var" statement). (These start out with the value undefined.)

Variables defined within the function

 

Let's look again at selected bits of the updateDisplay function from earlier:

 

function updateDisplay(panel, contentId)
{
    var url;

    // ...
}

And let's assume we call it with a reference to a 'leftPanel' div and a contentId of 123:

updateDisplay(leftPanel, 123);

That creates a call object for this execution of updateDisplay that essentially looks like this:

call.arguments = [leftPanel, 123]
call.arguments.callee = updateDisplay
call.panel = leftPanel
call.contentId = 123
call.url = undefined

 

 

 

 

This object is then used within the body of the function when the code uses the arguments panel or contentId, or the local variable url, etc.

This object will be used later during the execution of the function,

"But wait," you say. "I don't refer to an object when I use the arguments or variables in my function, I just use their names." Indeed — the use of the call object is implicit. How do we end up using the call object when we just write "contentId" (for instance)? Because once the call object is created, it's put at the top of the scope chain for the duration of the function call. Which takes us nicely to...

This object is a reference to the call is implicit, when the call object created during the execution of the function, the call object is placed on top of the scope chain

 

 

#2: Variable names are resolved using a "scope chain"

 

Multivariate analysis by "scope chain"

If you've written JavaScript in a browser environment, you've probably used the global document object, and perhaps the global navigator object as well. Here's the thing: Those aren't global objects. Those are properties of a global object — in fact, of the global object. The document and navigator properties are set up for you by the browser, but they're just properties of an object.

In the browser environment global document object and the navigator object is in fact not global objects, these are just a global object of properties, you are setting a good browser.

 

So how do you get away with just giving the property name, rather than giving the object name as well? Because of the scope chain, an ordered series (indeed, a chain) of objects. When the JavaScript interpreter sees an unqualified variable reference, it checks the top object on the scope chain to see if it has a property by that name: If so, it gets used; if not, the interpreter checks the next object down the chain. The global object is the bottom of the chain, so if you just type document.writeln("Blah blah blah"), eventually the document property is found on the global object and used.

By scope chain, when the js interpreter unreserved see a variable reference when it would have been looking down scope chain, global object at the very end of the scope chain, so when you hit document.writeln .. when will last find global object of this document properties and start using

 

(The global object is an abstract entity in the generic JavaScript definition, but in the specific case of a web browser you know it by another name: window. In browsers, the window object is the global object; it just also has a property, "window", that refers to itself.)

(Global object is JS definition of an abstract entity, in the browser, window is a true global object)

 

So quick: Within a function, how do variable names get resolved? Right! When the function is being executed, the call object with all those nifty properties for the function's arguments and variables is put at the top of the scope chain. So during our call to updateDisplay from earlier, the call object for the call is at the top of the scope chain, followed by the global object, like this:

So, when the function is executed, call object is created, and at the top of the scope chain:

 

 

 

When the interpreter sees a variable reference, say contentId, it looks on the call object: If there's a contentId property on the call object, it gets used; otherwise, the interpreter looks at the next object in the scope chain, which in this case is the global object.

So when the interpreter will find when looking ocntentId start call object if not looking up

 

(There's more to know about the scope chain than I've described here; the astute reader will be wondering, for instance, how objects and their instance members come into play, or what the with statement does to things. Alas, we can't tackle everything all at once...)

 

But how can I know when I'm writing updateDisplay that the scope chain will look like that? I mean, doesn't it depend on who's calling the function? Nope. And that brings us to our next point:

#3: Functions in JavaScript are lexically scoped                                                       

JS functions are lexical scope

Okay, so we get the concept of the call object, which is created when we call a function; and we get the global object, which sits at the bottom of the scope chain to handle globals. But what's this "lexically scoped" thing? It's just a fancy way of saying that a function's scope is determined by where it's defined (e.g., the text defining it; léxis is Greek for "word" or "speech"), not where it's called.

'Lexically scoped' mean the scope of a function by the local context is declared to decide instead of calling to decide

Let's put that another way: When a function is defined, the code defining it is in some kind of context — a function is running, or the page itself is running if you've done the code at the top level.

When the function is defined, and the function code defines the period over a period of contexts, as a function operation is performed to define the portion, or the entire outermost Script executed, to execute the code portion of the function definition.

That context has an active scope chain when the function is defined. So when creating the function object, the interpreter creates a property on it (called [[Scope]] in the ECMA spec, but you can't access it directly) with a reference to the active execution context's scope chain.

That there will be a context active scope chain, when creating a function of time, the interpreter will create a function object [[Scope]] property, pointing to the current active execution context of the scope chain

 

Even when the context goes away (e.g., the function returns), because the function object created by the definition has a reference to the scope chain, the scope chain isn't garbage collected — it's kept alive by the active reference to it from our function object.

Even when the switching time of the current context (such as the return function), since the function declaration cited scope chain,

sope chain is not garbage - because our function object also cited for it (- Annotation: Then look at the following paragraph, then .. because we also cited the function object, the function object also cited for it

 

 (Assuming that we've kept a reference to the function object, as we did in our example by passing it into the jsonRequest method; otherwise, the function and the scope chain are both garbage-collected since nothing references them.)

(We have to assume our function object reference as our example, it passed jsonRequest, otherwise the function and scope chain will be garbage collected, because nothing quote them)

 

 

Remember our closure at the beginning of this post? It gets a [[Scope]] property pointing to the scope chain in effect when updateDisplay was called with panel = leftPanel, etc.:

Remember closures mentioned at the beginning of the article we do, it has a [[Scope]] property, pointing to scope chain, when an incoming call is updateDisplay panel = leftPanel time, and so on ..

 

 

(Picture means: when the interpreter executes the callback to the closure, the top scope chain context call object updateDisplay is created, the bottom is global object, callback closure function object inside have a [[the Scope]] property points the scope chain

So when we call it, first its scope chain is put in place, then the call object for this particular call to the function is put on top of the scope chain, and the function is executed with this chain:

Then after the call began,

So when we called, it arranged the first scope chain is right, then call object is created and placed in the uppermost scope chain, then the function will be performed along the following chain:

 

 

 

 

 

And there we are, the closure can access panel and all of the other properties of the call object for the call to updateDisplay because they're on the scope chain. They're on the scope chain because that was stuck onto the closure's function object when it was created. No magic. Just objects, the scope chain, and lexical scoping all working together.

Then the closure will be able to access panel and all the other attributes of the call object updateDisplay invocation of the

 

 

#4: Closures don't cause memory leaks

Closure does not create a memory leak

So why do people think closures cause memory leaks? A couple of reasons, I suspect, but chief among them being a bug in an issue with Internet Explorer. IE's DOM objects are not garbage-collected in the same way that JavaScript objects are; instead, IE shows its COM roots by using reference counting, a mechanism that is, unfortunately, prey to issues with circular references. Event handlers can easily end up being circular references, and so in IE it's easy to "leak" the memory associated with a DOM element and its event handler because they're referring to each other. (JavaScript's garbage collector doesn't have an issue with circular references; it works on the "reachability" principle rather than reference counting.) This is an issue with event handlers, rather than closures, but since many event handlers are written as closures, people associate it with closures. Fortunately, it's not that hard to kick IE into shape (in this particular way); Crockford talks about the problem and its solution here and many toolkits [like Prototype] will do this for you if you ask them nicely.

Why do people think that the closure will cause a memory leak it?

It was previously a major problem in IE,

Garbage collection and standard of IE DOM objects of some js not the same.

IE using COM roots reference counting.

Not that cause a circular reference.

Event handlers can cause circulation even,

So ie between a DOM element and its event handler relatively easily lead to "leakage"

JS garbage collection mechanism would not have circular references, it is through the "reachability (reachability analysis)" is not a reference counting mechanism. This is an event handlers of the issue, rather than closure, but because a lot of event handlers are closures, so people put the matter and closures linked up. Luckily, it is very simple to repair. there are a lot of tools.

Lest I be accused of Microsoft-bashing, I should point out that IE is not the only browser that sometimes loses track of things; it's just by far the worst.

Microsoft said that I was black lest I should have to say IE is not the only browser such problems arise, it is just the worst,

Firefox 2 has a bad habit of leaking a bit of memory on XMLHttpRequest calls, which also frequently involve closures. The good news there is that Firefox 3 beta 3 is looking awfully good indeed on this front.

Firefox2 in XMLHttpRequest when the hair will be out of this problem

Separate from browser issues, though, if you're not really clear on how closures work, particularly with regard to the scope chain, you'll miss the fact that a closure keeps a reference to all of the variables and arguments in scope where it's created, not just the ones it uses;

If you do not really understand how it works closures, like those above, I say, do not understand the scope chain, in fact, you might not understand the closure retains all the variables and parameters of environment it creates, but it is not those variables and parameters used.

and so if you have (say) a massive temporary array allocated in that scope that the closure doesn't use, you might be tempted to say that the closure is causing the array's memory to leak. (The answer there is simple: Clear the array's variable when you're done with it.)

So if you have a huge array of temporary, in a scope, although actual closures are not using it, to say the mud could cause a memory leak closure array (if you can not stand, you can just clear this array variable)

 

In conclusion

in conclusion

There are lots of nifty things you can do with closures. I'll post a follow-up in a couple of days, "Closures By Example", demonstrating a few of them and just generally walking through some seemingly-complicated examples. But until then, I'll just reiterate my theme: Closures in JavaScript are not complicated. They're powerful, but if you understand that 1. Everything is a data structure, 2. Variables — I should probably call them unqualified references — are resolved according to a scope chain, and 3. The scope chain for a function is defined by where the function is defined lexically, you'll be golden.

For closures, there are many Sao operating behind me to demonstrate some of the content, but I'm still here I reiterate my theme:.. JavaScript is not complicated closures 1. You just need to understand that everything is data 2. variable structure - perhaps I should call them unqualified references (not retained, those references unprocessed) - will be resolved to deal with the scope chain 3. a function is defined by a function of the position declared by the scope chain decisions It is lexical.

Oh! I said I'd tell you something at the end that would surprise you for about three seconds before you said "Oh, of course." Here it is:

All JavaScript functions are closures.

The end I want to tell you a thing is,

All JavaScript functions are closures

- Annotation: meant to be here because all the internal functions have bindings, in fact, function js in essence is a kind of object, function call will be creating a lot of bindings, in line with the definition of a closure, A closure is a function with data intrinsically bound to it.

Guess you like

Origin www.cnblogs.com/eret9616/p/11618237.html