(翻译) How variables are allocated memory in Javascript? | scope chain | lexicial scope

Summary : Read the following article needs 15 Fenzhong

Question Asker is JavaScript in the memory is how allocated , in the process of introduction involves meter to the JS in the Scope Chain and call the function call generated lexicial environment and environment record ( the author merger called binding objects) process . Well worth Look

 

 

Personal Translator :

 

How variables are allocated memory in Javascript?

 

 

It's actually a very interesting area of JavaScript, and there are at least two answers:

  • An answer in terms of what the specification defines, and
  • An answer in terms of what JavaScript engines actually do, which may be optimized (and often is)

 

 

In fact, this is part of JavaScript content is very interesting. You can check the specific specifications,

Here are two directions refer to the answer:

  1. Specifications in terms of how it is defined ..
  2. Js engine on particular terms .. is how to do (these engines also typically contain a number of optimized content)

 

 

In terms of the specification: JavaScript's way of handling local variables is quite different from the way C does it. When you call a function, amongst other things a lexical environment for that call is created, which has something called an environment record. To keep things simple, I'm going to refer to them both together as the "binding object" (there's a good reason they're separate in the specification, though; if you want to get deeper into it, set aside a few hours and read through the spec).

 

On standardized terms, Javascript handling local variables of the C language and there are some ways not the same as when you call (call) a function,

 

It creates a lexical environment,

Will include an internal environment record,

 

For simplicity, I'll merge with them called 'binding object' (in the specification they are separate, if you want a better understanding, you can go to regulate their own.)

 

 

 

The binding object contains bindings  for the arguments to the function, all local variables declared in the function, and all functions declared within the function (along with a couple of other things).

 

binding object contains   Bindings, including function arguments, local variables inside a function definition, function definitions and function of the internal (also contains something else)

 --- Translation: A person though did not say, but I think it should be also included this

 

 

binding is a combination of a name (like a) and the current value for the binding (along with a couple of flags we don't need to worry about here).

 

binding refers to a set of bindings name and current value

 

 

An unqualified reference within the function (e.g., the foo in foo, but not the foo in obj.foo, which is qualified) is first checked against the binding object to see if it matches a binding on it; if it does, that binding is used.

 

 Not found references (such as looking for a direct reference to foo, instead of referencing obj.foo) will start binding object where to find, if it will use this binding

 

 

 

 

 

 

When a closure survives the function returning (which can happen for several reasons), the binding object for that function call is retained in memory because the closure has a reference to the binding object in place where it was created. So in specification terms, it's all about objects.

 

 

If the function return after the finish retains a closure (closure), the function call (call) generated by the binding object will be retained in memory, because the closure cited the binding object. So we specifications, these variables They are declared in the object (it is all about objects - Annotation: here refers to the object, C / C ++ object in general objects stored on the heap memory).

 

 

 

 

At first glance, that would suggest that the stack isn't used for local variables; in fact, modern JavaScript engines are quite smart, and may (if it's worthwhile) use the stack for locals that aren't actually used by the closure. They may even use the stack for locals that do get used by the closure, but then move them into an binding object when the function returns so the closure continues to have access to them. (Naturally, the stack is still used for keeping track of return addresses and such.)

 

Such a look, like local variables are not stored in the stack (as it will be referenced has persisted even after the memory heap). In fact, modern JavaScript engines are very smart very high, and it is possible to use the stack to store a local variable is not referred closure, but when the function returns to the binding object will move them so that closures can continue to access them (of course, still be used to track Stack function return address ..)

 

 

Here's an example:

function foo(a, b) {
    c;
 
    c = a + b;
 
    function bar(d) {
        alert("d * c = " + (d * c));
    }
 
    return bar;
}
 
var b = foo (1, 2);
b(3); // alerts "d * c = 9"

 

 

When we call foo, a binding object gets created with these bindings (according to the spec):

  • a and b — the arguments to the function
  • c — a local variable declared in the function
  • bar — a function declared within the function
  • (...and a couple of other things)

 

When calling foo creates a binding object, which has these bindings:

  1. a and b - arguments of the function)
  2. C- function defined within a local variable
  3. A function definition function within bar-
  4. (... and some other stuff)

 

 

When foo executes the statement c = a + b;, it's referencing the ca, and b bindings on the binding object for that call to foo.

 

When foo returns a reference to the bar function declared inside it, bar survives the call to foo returning. Since bar has a (hidden) reference to the binding object for that specific call to foo, the binding object survives (whereas in the normal case, there would be no outstanding references to it and so it would be available for garbage collection).

 

When performing foo to c = a + b; time

Object references binding of c, a, b of these binding

 

When foo returns a reference to the time bar, bar to be preserved, because the bar has a reference to the binding object, so the binding object has also been retained (not referenced under normal circumstances, then it should be a garbage collector)

 

 

Later, when we call bar, a new binding object for that call is created with (amongst other things) a binding called d — the argument to bar. That new binding object gets a parent binding object: The one attached to bar. Together they form a "scope chain".

Unqualified references within bar are first checked against the binding object for that call to bar, so for instance, d resolves to the d binding on the binding object for the call to bar.

 

Then, when we call bar, and a new generation of binding object, which is called a binding d - the parameter bar, the binding object father is the original binding object, they formed a "scope chain" scope chain together. will search function is not referenced in the bar reserved, for example d is parsed became d binding, but

 

But an unqualified reference that doesn't match a binding on that binding object is then then checked against its parent binding object in the scope chain, which is the binding object for the call to foo that created bar. Since that has a binding for c, that's the binding used for the identifier c within bar. E.g., in rough terms:

 

But can not find in the binding object is referenced, the next will be on top of its scope chain binding object to find his father, binding object foo is there a c, so that c binding was then bar inside c identifier used, roughly speaking:

 

 

+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|   global binding object   |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| ....                      |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
             ^
             | chain
             |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| `foo` call binding object |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| a = 1                     |
| b = 2                     |
| c = 3                     |
| bar = (function)          |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
             ^
             | chain
             |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| `bar` call binding object |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| d = 3                     |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−+

Fun fact: This scope chain is how global variables work in JavaScript. Note the "global binding object" in the above. So in a function, if you use an identifier that isn't in the binding object for that function call, and isn't in any of the other binding objects between that and the global binding object, if the global binding object has a binding for it, the global binding is used. Voilà, global variables.

 

The scope chain is in the works JavaScript global variables are labeled "globall binding object"

 

If you use a binding object identifier but not in a function call produced in, would have been looking up in a function, until the global binding object.

 

 

 

(ES2015 made this a bit more interesting by having two layers to the global binding object: A layer used by old-fashioned global declarations like var and function declarations, and a layer used by newer ones like letconst, and class.

The difference is that the older layer also creates properties on the global object, which you kind of access via window on browsers, but the newer layer doesn't. So a global let declaration doesn't create a window property, but a global var declaration does.)

 

ES2015 By adding two to the global binding object to make this more interesting part of some

One is using the old-style global declarations such as var and function declarations, another with an updated let const class image.

The difference is that the old layer creates properties on the global object, you can through the browser window to access , but the new one can not be

So, let a global declaration does not create in the window, but a global var statement creates a window in the property

 

 

 

 

Implementations are free to use whatever mechanism they want under the covers to make the above seem to happen.

It's impossible to get direct access to the binding object for a function call, and the spec makes clear that it's perfectly fine if the binding object is just a concept, rather than a literal part of the implementation.

Specific implementation will be based on the implementation mechanism of the engine is different

binding object can not be generated directly to get the function call

And the specification say there are actually binding object of this concept can be, and no specific details concerning the mechanism to achieve

 

A simple implementation may well just literally do what the spec says; a more complicated one may use a stack when there are no closures involved (for the speed benefit), or may always use a stack but then "tear off" the binding object needed for a closure when popping the stack. The only way to know in any specific case is to look at their code. :-)

A simple implementation as will literally do specification, will be more complex in order to optimize the introduction of the stack when it comes to these Closures .. Unless you look engine code.

 

 

 

More about closures, the scope chain, etc. here:

 

 

 

 

Information: specifications for a shot on the lexial environment

 

Guess you like

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