Accessing context property of a function object | How to? - javascript

Each function object should have two "hidden" properties ( per JavaScript The Good Parts, The Functions Chapter )
context
and
code
Is there a way to access these properties?

Well, you can access the function code pretty easily - by using toString() (or Mozilla's non-standard toSource()):
var x = function() { alert('Here is my happy function'); };
console.log(x.toString());
As for context, I suppose DC meant more than simple this, and actually wrote about Execution Context.
UPDATE: Have found an interesting snippet in ES5 specification, where these two properties are actually described in some details - and not as abstract concepts:
13.2 Creating Function Objects
Given an optional parameter list specified by FormalParameterList, a
body specified by FunctionBody, a Lexical Environment specified by
Scope, and a Boolean flag Strict, a Function object is constructed as
follows:
...
Set the [[Scope]] internal property of F to the value of Scope.
...
Set the [[Code]] internal property of F to FunctionBody.
At the same time:
Lexical Environments and Environment Record values are purely
specification mechanisms and need not correspond to any specific
artefact of an ECMAScript implementation. It is impossible for an
ECMAScript program to directly access or manipulate such values.
So I guess that closes the question about accessing Scope property of function.
As for Code property, its read-only accessing with toString(), as was rightly noticed by Matt, is implementation-dependent - yet is more often implemented than not. )

Related

Understanding how Javascript resolving variables globally

If I open a javascript console on a web page and add a variable:
var abc = "Hello";
Javascript attaches that property to the window object so I can simply access the object by window.abc or directly abc
console.log(window.abc)
console.log(abc)
Now, if I try to access something not defined yet through the window object
console.log(window.notdefinedyet)
> undefined
It simply returns undefined. So if I do
console.log(notdefinedyet)
why is that an error and not just undefined?
Because trying to read the value of an undeclared identifier is a ReferenceError. This is fundamentally a different operation from trying to read a property from an object that the object doesn't have.
Trying to use an undeclared identifier is usually a bug (for instance, a typo). That's part of why ES5's strict mode made assigning to an undeclared identifier a ReferenceError (instead of the old behavior — still in loose mode for backward-compatibility — where it creates a new global variable, something I call The Horror of Implicit Globals).
One could argue (and many have) that trying to get a property from an object that the object doesn't have is also a bug. But it's often really useful to get undefined instead of an error in that case. Whether one agrees with that distiction, this is how JavaScript is defined.
It's probably worth noting tangentially that this business of global variable declarations creating properties on the global object is legacy behavior that has to remain in place for backward compatibility, but isn't consistent with current thought on language design in TC39 (the committee behind JavaScript standards). Newer constructs like let, const, and class don't create properties on the global object even when used at global scope (although they do create globals):
var a = 1;
let b = 2;
console.log("a" in window); // true
console.log("b" in window); // false
console.log(a); // 1
console.log(b); // 2
It always check for reference so console.log(notdefinedyet) gives an error but in case of console.log(window.notdefinedyet), window has reference of object type built in only thing it does not have notdefinedyet key

How are Function objects different from Normal objects?

How are functions stored in a variable?
According to MDN
In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.
Suppose this scenario,
var fn = function () {};
fn.attr = 3;
console.log(fn); //prints function() {}
console.log(Object.keys(fn)); //prints ["attr"]
If a function is an object shouldn't it have keys and value kind where the function is stored in a property and the interpreters don't show that property? Something like C++ style operator overloading or array/object representation in Javascript itself. I mean to say are functions (or arrays) are just objects treated in a different manner? Which might imply that anonymous functions are stored in an object with a hidden property.
In summary, what is the underlying working of functions(or arrays)? Are they treated specially? Or are they just syntactic sugar for some hidden property which is called when () is used?
Yes, functions are special.
Proof
const f = Object.create(Function.prototype);
f(); // TypeError: f is not a function
Exposition
They are "callable objects" that can only be created via prescribed syntax (function expressions, statements, declarations, fat-arrows, object literal method definition shorthand, Function constructor, class methods).
That means they have a special [[Call]] method (not visible to you) that is called when you invoke them with the () syntax.
[[Call]] coordinates:
the creation of the execution context (call-stack frame)
addition of the new execution context to the top of the stack
execution of the function logic
removal of the execution context from the stack
cueing up the next context to run (the one immediately lower on the stack)
supplying any return value to the next execution context
Creation of the execution context in turn completes configuration of the LexicalEnvironment (used for scoping), configuration of the receiver (this) for the function and other meta-logic.
Functions also differ from most normal objects in that they have Function.prototype on their [[Prototype]] chain (although you can create your own 'useless' object by inheriting from Function.prototype - see above).
For a full list of differences, please see MDN, the spec etc.

JavaScript function length and arguments properties/fields

I am a newbie to js although years of experience with Java
I suppose when I declare a function,it is essentially a special type of object,and got some builtin fields that are accessible directly such as "arguments" and "length"
I notice I can access something like "arguments" inside the scope of a function
i.e.
function add(a,b) {
return arguments[0]+arguments[1]
}
Also I can access something like "length" outside the scope
//2
alert(add.length)
the above snippet should be the right way to use
however
function sum(a,b) {
// error
return length
}
// null
alert(sum.arguments)
I suppose arguments and length are not of the same basic, is it right idea?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After some research,I got the root cause of the confusion.
The issue revolves around property VS variable in JavaScript
Property belong to Object while Variable belong to Context.
The two ideas can be interchangeable sometimes:
The global context happen to be window
<script>
//property
window.foo="a"
//variable
var bar="b"
//a
alert(foo)
//b
alert(bar)
</script>
In most scenario,say,function context,they are completely different ideas,partly because you can never access the function object in your code.Thus,contrary to a global setting ,assign a property is impossible! What is possible is just declare a variable in scope
In my question
"arguments" is a variable
while "length" is a property
I failed to distinguish the two
For more information,please refer to
this post
Functions are objects in JavaScript. Proper, real objects.
length
The length property of a function is the number of declared arguments it has (this is also called the "arity" of the function). The arity (length) of add is two because you declared two formal arguments for it: a and b.
arguments
The arguments pseudo-array is not part of the function object. It's an object created when the function is called, and only in scope within that function call's context. It contains all of the arguments that the function was actually called with, which can be different from the number of arguments it declares. Each separate call to the function gets its own separate arguments object.
In JavaScript's "loose mode" (the only mode it had before 2009's ECMAScript 5th edition specification), there's a live connection between the arguments pseudo-array and the declared arguments:
// In loose mode only
function foo(a) {
console.log("a = " + a);
console.log("arguments[0] = " + arguments[0]);
a = 42;
console.log("a = " + a);
console.log("arguments[0] = " + arguments[0]);
}
foo(67);
In loose mode, that outputs:
a = 67
arguments[0] = 67
a = 42
arguments[0] = 42
In "strict" mode (which is the preferred mode to use), that link doesn't exist (we'd see arguments[0] = 67 at the end), which is useful for JavaScript engines for optimization purposes.
Yes, length and arguments are different concepts.
Contrary to Java, where fields (attributes) of your object, methods, and local variables are all accessible in the same scope (just via an identifier), JavaScript does distinguish heavily between scope variables (with closures, lexically referenced) and object properties (possibly inherited) - not only in concept, but also in syntax. Properties are always1 accessed via . or [] notation.
The .length of Function instances is such a property. You will always have to write add.length or sum.length (or …["length"]). If you just use length inside of the function, it doesn't automatically refer to the property - it's a variable reference, in this case to an undeclared one.
The arguments object in contrast works like a variable. It cannot be accessed as a property of the function2. Admittedly, it's a bit special, because you cannot see the declaration of the variable - it is created implicitly in every function scope. It works a bit as if there was a const arguments = {0: a, 1: b}; statement in the first line of the function.
1: Not exactly true, there's a with statement that explicitly lifts object properties into a scope. It's despised due to its ambiguity and deprecated in strict mode though.
2: There also is a deprecated .arguments property on functions, accessing it on strict mode functions throws. If not accessed during the invocation, it's null.

Why do variables become keys on the window object?

I've noticed that variables become keys and their values become values of said keys when I am writing on the window object. For instance:
var variable = "value";
console.log(window.variable);//logs "value"
But if I create a new object of my own like:
var o = {
key: "value",
var key2 = "value2"
}; // result: "syntax error"
I have to use the colon to set key/value pairs. And even with constructor functions, although I don't get a syntax error, I don't seem to be able to do this inside the constructor function or during object instantiation or after:
function Blueprint(){
this.key = "value";
var key2 = "value2";
}
var o = new Blueprint;
console.log(o.key); //result: "value"
console.log(o.key2); //result: "undefined"
Now, I understand why, in the former case, I generated a syntax error and why in the latter case I was unable to attach key2 to the Blueprint constructor function but what I don't understand why on the global window object I am given free range to just add properties using variables and they instantly become keys on the window object. Other than on the windows object, variables seem to behave as though they are independent of objects and property creation.
I've also noticed similar behavior on the global object when experimenting with node. Are global objects the only objects that can set key/value pairs in this way using variables? And if so, why? Why aren't we forced to do something like the following when working on the global level:
this.key = "value";
Or...
window.key = "value";
Is this just some caveat to the behavior of the language overall or is there some internally consistent logic about the window object in relation to all other objects that explains this?
Global variables (as opposed to local variables declared within a function) become properties of the global object.
In a browser, the global object is window.
The global environment is a so called Object Environment (Record):
Each object environment record is associated with an object called its binding object. An object environment record binds the set of identifier names that directly correspond to the property names of its binding object.
As you can see, the behavior to create properties for identifiers is explicitly defined. And in the case of the global environment, the binding object is the global object, which is window in browsers.
More detailed information about environments can be found in the spec:
There are two kinds of Environment Record values used in this specification: declarative environment records and object environment records. Declarative environment records are used to define the effect of ECMAScript language syntactic elements such as FunctionDeclarations, VariableDeclarations, and Catch clauses that directly associate identifier bindings with ECMAScript language values. Object environment records are used to define the effect of ECMAScript elements such as Program and WithStatement that associate identifier bindings with the properties of some object.
I can't tell you why these two types exist. If you want to know that, you could ask at http://esdiscuss.org/

Enclosure Memory Copies

function myClass()
{
//lots and lots of vars and code here.
this.bar = function()
{
//do something with the numerous enclosed myClass vars
}
this.foo = function()
{
alert('Hello'); //don't do anything with the enclosed variables.
}
}
Each instance of myClass gets its own copy of bar and foo, which is why prototyped methods use less memory. However, I would like to know more about the memory use of inner methods.
It seems obvious to me that (1) below must be true. Do you agree?
Not only do distinct myClass instances have their own distinct copies of bar, but they also must have their own distinct copies of the myClass enclosure. (or else how does the bar method keep the myClass variables straight on a per instance basis?)
Now (2) is the question I'm really after.
Since the inner foo method doesn't use anything in the myClass enclosure a natural qustion is: Is javascript smart enough to not keep a myClass enclosure in memory for the use of foo?
This will depend entirely on the implementation not the language. Naive implementations will keep far more around than others. Any answer that is true for e.g. V8 (chrome's JS engine) may not be true for Spidermonkey (Firefox's) or JScript (IE) etc...
In my experience (this is definitely how GHC handles closures), the actual code of the functions (inner or outer) only exists once, but an "environment" mapping variables to values must be kept around for the closure (bar), so no, I wouldn't expect the JS implementation to keep around more than one copy of MyClass, but it will keep around a copy of its environment at least with this.bar, sensible implementations might realize that no environment is actually needed foo is not actually a closure, and thus does not need to keep a copy of the environment from the call to MyClass however do not rely on this behaviour.
Especially since the behavior of JS's eval function which evaluates a string in the same lexical environemnt as the eval call, it is quite likely that JS implementations always keep the lexical environment around.
I'm reasonably certain that any function has the a pointer to the entire state. It's irrelevant whether it references any variables it still has access to them.
Of course you do release that both bar & foo point to the same "entire state" of the object. So it doesn't take any more memory. I guess you have to allocate one more pointer internally so you can point to the "entire state" of the object but optimising for something like that is silly.
Whether it optimises it away is javascript engine specific. By all means read the chromium source and find out.
I'll see if I can dig some quotes out of the spec for you.
Entering Function code from the spec:
10.4.3 Entering Function Code The following steps are performed when
control enters the execution context
for function code contained in
function object F, a caller provided
thisArg, and a caller provided
argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the
global object.
Else if Type(thisArg) is not Object, set the ThisBinding to
ToObject(thisArg).
Else set the ThisBinding to thisArg.
Let localEnv be the result of calling NewDeclarativeEnvironment
passing the value of the [[Scope]]
internal property of F as the
argument.
Set the LexicalEnvironment to localEnv.
Set the VariableEnvironment to localEnv.
That tracks your environment to NewDeclarativeEnvironment.
NewDeclarativeEnvironment
10.2.2.2 NewDeclarativeEnvironment (E) When the abstract operation
NewDeclarativeEnvironment is called
with either a Lexical Environment or
null as argument E the following steps
are performed:
Let env be a new Lexical Environment.
Let envRec be a new declarative environment record containing no
bindings.
Set env’s environment record to be envRec.
Set the outer lexical environment reference of env to E.
Return env.
This tracks your environment to E which is the [[Scope]] of the function Object
13.2 Creating Function Objects Given an optional parameter list specified
by FormalParameterList, a body
specified by FunctionBody, a Lexical
Environment specified by Scope, and a
Boolean flag Strict, a Function object
is constructed as follows:
Create a new native ECMAScript object and let F be that object.
Set all the internal methods, except for [[Get]], of F as described
in 8.12.
Set the [[Class]] internal property of F to "Function".
Set the [[Prototype]] internal property of F to the standard built-in
Function prototype object as specified
in 15.3.3.1.
Set the [[Get]] internal property of F as described in 15.3.5.4.
Set the [[Call]] internal property of F as described in 13.2.1.
Set the [[Construct]] internal property of F as described in 13.2.2.
Set the [[HasInstance]] internal property of F as described in
15.3.5.3.
Set the [[Scope]] internal property of F to the value of Scope.
Let names be a List containing, in left to right textual or
Turn's out the spec is just telling you things you already know. Every functions contain the Scope. As the other poster mentioned it is upto individual implementation to "optimise" some of the scope away in terms of memory management.
If you ask me you really don't care about this unless you have >million instances of these objects.
The following block from the spec is more applicable:
The outer environment reference is
used to model the logical nesting of
Lexical Environment values. The outer
reference of a (inner) Lexical
Environment is a reference to the
Lexical Environment that logically
surrounds the inner Lexical
Environment. An outer Lexical
Environment may, of course, have its
own outer Lexical Environment. A
Lexical Environment may serve as the
outer environment for multiple inner
Lexical Environments. For example, if
a FunctionDeclaration contains two
nested FunctionDeclarations then the
Lexical Environments of each of the
nested functions will have as their
outer Lexical Environment the Lexical
Environment of the current execution
of the surrounding function.
The two nested functions both have the same reference to the outer Lexical Environment
Well, let's ask some implementations what they do, shall we :-)
Spidermonkey: Internals-Functions -- agrees with other answers. Talks about how closures can be classified.
V8: Are Closures Optimized -- very terse but does mention "static optimizations". Various articles on the web talk about "hidden classes" which, I believe, are how the V8 GC tries to optimize closures.
Sadly those meager links are about all I can find. A direct analysis of the engine source-code is likely required to add more meaningful input.
So, yes, different engines do implement different optimization strategies when they can.

Categories