Assuming I had this sloppy-mode function, which (for some odd reason) returns its arguments object to the caller:
function example(a, b/* ...*/) {
var c = // some processing
return arguments;
}
Does storing the result of an invocation (var d=example();) prevent the variable environment of example (containing a, b, c etc) from being garbage-collected? The internal setters and getters of the Arguments object might still refer to it, just like a function returned from a closure does. Demo:
function example(a, b) {
var c = Array(1000).fill(0); // some large object
return {
args: arguments,
set: function(x) { a = x; },
get: function() { return a; }
};
}
var d = example('init');
console.log(d.get());
d.args[0] = 'arguments update'; // assigns the `a` variable
console.log(d.get());
d.set('variable update');
console.log(d.args); // reads the `a` variable
I know there is hardly a use case (and passing around Arguments objects is considered bad practice, most likely because of their similarity to arrays), but this is more a theoretical question. How do different EcmaScript implementations handle this? Is it implemented close to the spec?
I would expect c to be garbage-collected like with a normal closure and not to be leaked, but what about b? What would happen if I delete the properties of the arguments object?
Consider this:
var x = function() {
return arguments;
}
console.log( x() === x() );
It's false, because it's not the same arguments object: it's (for each invokation of x) a newly constructed object that has the values of all the params stored within. Yet it has properties of arguments:
var y = x([]);
console.log(y instanceof Object); // true
console.log(y instanceof Array); // false
console.log(y.length); // 1
console.log(y.callee + ''); // function() { return arguments; }
Yet there's more to this. Obviously, objects sent into function as its params will not be collected by GC if arguments are returned:
var z = x({some: 'value'});
console.log(z[0]); // {some:'value'}
This is expected: after all, you can get the similar result by declaring some local object inside the function, assigning the value of the function's first parameter as its object '0' property, then returning this object. In both case the referred object will still be "in use", so no big deal, I suppose.
But what about this?
var globalArgs;
var returnArguments = function() {
var localArgs = arguments;
console.log('Local arguments: ');
console.log(localArgs.callee.arguments);
if (globalArgs) { // not the first run
console.log('Global arguments inside function: ');
console.log(globalArgs.callee.arguments);
}
return arguments;
}
globalArgs = returnArguments('foo');
console.log('Global arguments outside function #1: ');
console.log(globalArgs.callee.arguments);
globalArgs = returnArguments('bar');
console.log('Global arguments outside function #2: ');
console.log(globalArgs.callee.arguments);
Output:
Local arguments: ["foo"]
Global arguments outside function #1: null
Local arguments: ["bar"]
Global arguments inside function: ["bar"]
Global arguments outside function #2: null
As you see, if you return arguments object and assign it to some variable, inside the function its callee.argument property points to the same set of data as arguments itself; that's, again, expected. But outside the function variable.callee.arguments is equal to null (not undefined).
Without having done any research into a particular JavaScript engine this is hard to answer conclusively. I would however argue that the relation between the arguments Object and the context created by example is the same as of any other local variable and its host context.
That is to say, storing the value does not require its context to be stored as well.
One caveat is the arguments.callee property which is a reference to the context (i.e. Function) which a given arguments Object is bound to. This property however does not exist in strict mode and also has been deprecated.
Other than that I think it's safe to assume that returning and storing the arguments Object won't lead to a memory leak.
Related
How can I compare functions which were bounded before independently on context (this).
I know that Function.prototype.bind returns new function but is it possible to find out reference to the original function?
Let's say I want to implement function equalsOrigins to do it for me:
var func1 = someFunction.bind(obj1);
var func2 = someFunction.bind(obj2);
var func3 = otherFunction.bind(obj1);
func1 === func2; // naturally returns false
equalsOrigins(func1, func2); // should return true
equalsOrigins(func1, func3); // should return false
equalsOrigins(func2, func3); // should return false
Is that possible in javascript?
Is it possible to find out reference to the original function?
No, not without access to the engine internals or a debugger. The bound function does contain a reference to the target function, but it is not accessible.
Your best bet, if the function does not throw or return an object, might be to abuse it as a constructor, and reconstruct the reference from the prototype object.
function example() { /* sane */ }
var bound = example.bind({});
Object.getPrototypeOf(new bound).constructor == example // true
In JavaScript, can I enumerate the bound arguments for a function?
function foo(a, b) {}
foo = foo.bind(null, '1');
How can I tell that a has been bound to '1'?
Not sure if I understood your question correctly. However, here is a hacky way to get all currently bound arguments of a function.
It works by overwriting the native bind method and storing all bound arguments in a property of the newly bound function.
Function.prototype.bind = (function() {
var bind = Function.prototype.bind;
var slice = Array.prototype.slice;
return function() {
// bind the function using the native bind
var bound = bind.apply(this, arguments);
// store the bound arguments in a property of the bound function
bound.bArgs = (this.bArgs || []).concat(slice.call(arguments, 1));
return bound;
};
})();
function foo(a, b) {}
foo = foo.bind(null, '1');
console.log(foo.bArgs); // ["1"]
foo = foo.bind(null, '2');
console.log(foo.bArgs); // ["1", "2"]
http://jsfiddle.net/49d1xfns/
You cannot. The function is simply being called passed a certain this value and optionally certain argument values: it's not a problem of the called function to distinguish who has been passing those values...
To simplify a bit the issue consider:
function add(x, y) {
return x + y;
}
function bind_first(f, x) {
return function(y) { return f(x, y); };
}
var add3 = bind_first(add, 3);
console.log(add3(2)); // ==> output is 5
the add function is called with two arguments as usual... both of them are coming from the body of an anonymous closure created by bind_first and it's it's nothing that should interest add how this anonymous closure computed the value of those parameters... got them from the outside? were captured variables? computed them itself? are constants?... WHO CARES!
In other words if you want to be able to differentiate between a bound argument and a regular argument there's for sure something wrong in your design (it's none of your business :-) ).
To know how many explicit arguments were bound to a particular function, you'd need to know:
The number of explicit arguments in the original function
The number of explicit arguments in the bound function
This can be achieved if you have access to both the original function and the newly bound function. This also assumes that the binding was done with an ES5 compliant Function.prototype.bind call.
The way you'd figure out which arguments were bound is by subtracting the newly bound function's length from the original function's length:
var foo = function (a, b, c) {...};
var bar = foo.bind(fizz, buzz);
var argumentsBound = foo.length - bar.length; // 1
var argumentNames = ['a', 'b', 'c'].slice(0, argumentsBound); // 'a'
Details for why this works can be found in the ES5 spec (15.3.4.5, #15)
If the [[Class]] internal property of Target is "Function", then
Let L be the length property of Target minus the length of A.
Set the length own property of F to either 0 or L, whichever is larger.
All of that said, this doesn't give much access at all to which properties were bound, and is pretty well useless within the original function (foo in my example above) because the original function probably shouldn't reference bound derivative functions.
This also doesn't help at all if no arguments are defined on the function. If you're making use of arguments to pass additional parameters, the length property is no longer relevant.
(Question 1)
In Flanagan's JS Definitive Guide, he defines the Function method bind() in case it's not available (wasn't available n ECMAScript 3).
It looks like this:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
He illustrates the use of it with an example (which I have modified to change the 3rd line from f.bind(o)):
function f(y) { return this.x + y; } // This function needs to be bound
var o = { x : 1 }; // An object we'll bind to
var g = bind(f, o); // Calling g(x) invokes o.f(x)
g(2) // => 3
When I first saw this, I thought "Wouldn't arguments refer to the arguments variable within the bind function we're defining? But we want the arguments property of the function we eventually apply it to, like g in the example above..."
I verified that his example did indeed work and surmised that the line return f.apply(o, arguments) isn't evaluated until var g = bind(f, o) up above. That is, I thought, when you return a function, are you just returning the source code for that function, no? Until its evaluated? So I tested this theory by trying out a slightly different version of bind:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
If it's simply returning tbe unevaluated function source, there's no way that it stores arguments = 6 when later evaluated, right? And after checking, I still got g(2) => 3. But then I realized -- if it's just returning unevaluated code, how is the o in return f.apply(o, arguments) getting passed?
So I decided that what must be happening is this:
The o and the arguments variables (even when arguments equals 6) are getting passed on to the function. It's just that when the function g is eventually called, the arguments variable is redefined by the interpreter to be the arguments of g (in g(2)) and hence the original value of arguments that I tried to pass on was replaced. But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
(Question 2) Earlier on the same page, he defines the following function which makes use the apply method to trace a function for debugging:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
Question 1
For your first question, let's simplify the example so it's clear what being done:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
What happens here is that a closure is created that allows the access of the original function and the value of this that is passed. The anonymous function returned will keep the original function in its scope, which ends up being like the following:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
About your issue with arguments, that variable is implicitly defined in the scope of all functions created, so therefore the inner arguments will shadow the outer arguments, making it work as expected.
Question 2
Your problem is to your misunderstanding of the late binding of this -- this is one of the more confusing things about JavaScript to people used to more object-oriented languages that also have their own this keyword. The value of this is only set when it is called, and where it is called defines the value of this when it is called. It is simply the value of the parent object from where it is at the time the function is called, with the exception of cases where the this value is overridden.
For example, see this:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
If this was set when the function was defined, calling b.a would result in the global object, not the b object. Let's also simplify what happens with the second function given:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
What happens in this case is that the original method is stored in a closure. Assigning to the object that the method was originally in does not overwrite the method object. Just like a normal method assignment, the principles of the this value still work the same -- it will return the parent object, not the function that you've defined. If you do a simple assignment:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
It does what was expected, returns the parent object at the time of calling. Placing your code in a nested function makes no difference in this regard.
Some good resources
If you'd like to learn more about writing code in JavaScript, I'd highly recommend taking a look at Fully Understanding the this Keyword by Cody Lindley -- it goes into much more detail about how the this keyword behaves in different contexts and the things you can do with it.
But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
No. this and arguments are just special variables which are implicitly set when a function is executed. They don't adhere to normal "closure rules". The function definition itself is still evaluated immediately and bind returns a function object.
You can easily verify this with:
var g = bind(f, o);
console.log(typeof g);
Here is a simpler example which doesn't involve higher order functions:
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);
I think you see that the definition of foo is evaluated like you'd expect. Yet, console.log(arguments) logs [1, 2] and not 42.
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
this never refers to the function itself (unless you explicitly set it so). The value of this is completely determined by how the function is called. That's why this is often called "the context". The MDN documentation provides extensive information about this.
Reading material:
MDN - this
MDN - arguments
Regarding this code:
var name = "Jaguar";
var car = {
name:"Ferrari",
getName:function(){
return this.name;
}
};
alert((car.getName = car.getName)());
The output is: Jaguar.
Why does this object correspond to Window and not the object contained in the car variable?
It seems that the fact to reassign the object's function to itself leads to lose the assignment of this to the object when the function is called...
I'm trying to guess: Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
The reason is fairly subtle: this in JavaScript is determined entirely by how a function is called. To have this set to car during the call to getName, you have to call getName immediately upon retrieving it from the car object, like this:
car.getName() // or
car["getName"]()
(Or via Function#call or Function#apply, which let you specify the value for this explicitly.)
What you're doing in your example is effectively this:
// Set f to the result of the assignment expression,
// which is a reference to the getName function
var f = (car.getName = car.getName);
// Call it (separately)
f();
...which is different. Functions called in that way get this set to the global object (window, in browsers). (Except in strict mode; in strict mode this would be undefined.)
More (from my anemic blog):
Mythical methods
You must remember this
Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
I'm not entirely sure I follow that question, but if you want to have a function that always has a preset this value, then yes, there are a couple of ways to do that.
One is to use the new ES5 function bind:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = function(){
return this.name;
}.bind(car);
alert((car.getName = car.getName)()); // "Ferrari"
bind returns a function that always has this set to the argument you give it.
The other way is to use a closure. And in fact, you can create a bind-like function in ES3 very easily:
function pseudoBind(func, thisArg) {
return function() {
return func.apply(thisArg, arguments);
};
}
That doesn't do everything bind does, but it does the this part. Then you'd have:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = pseudoBind(function(){
return this.name;
}, car);
alert((car.getName = car.getName)()); // "Ferrari"
More on closures (again from the blog):
Closures are not complicated
In a future spec, we'll be getting a declarative way of creating functions that have a preset this value (so-called "arrow functions" because the syntax for them involves uses => rather than the function keyword).
Aaah, this resolution...Lets take a gander.
var toy = {
log : function () { console.log(this); }
};
toy.log() //logs the toy object
So far, it seems like this resolution is static: Wherever the method was defined in, that's its this value.
But! What if we do this:
var sneakyBastard = toy.log;
sneakyBastard(); //logs Window
this is bound to the object it's called with. In the case of toy.log, you called log in the context of the toy object. But, sneakyBastard has no set context, so it's as if you've called window.sneakyBastard.
Now let's take a goose (goose? gander? no...) at your expression:
(car.getName = car.getName)()
...and what does an assignment return? The assigned value, in this case, a function, car.getName. We can break this expression into two:
var returnedValue = (car.getName = car.getName);
returnedValue();
...and from here it's obvious.
Instead of calling getName from the context of an object, you're calling it from the context of the return result of the grouping operator (which in this case there's no context).
In JavaScript, when there's no clear context defined, a default is used. The default is...
the global object when in strict mode
undefined when not in strict mode
You have put your function call parenthesis (()) so they call the result of the expression (car.getName = car.getName) (which is the value (a function) assigned to car.getName)
I have been doing a lot of research on this lately, but have yet to get a really good solid answer. I read somewhere that a new Function() object is created when the JavaScript engine comes across a function statement, which would lead me to believe it could be a child of an object (thus becoming one). So I emailed Douglas Crockford, and his answer was:
Not exactly, because a function
statement does not call the compiler.
But it produces a similar result.
Also, to my knowledge, you can't call members on a function constructor unless it has been instantiated as a new object. So this will not work:
function myFunction(){
this.myProperty = "Am I an object!";
}
myFunction.myProperty; // myFunction is not a function
myFunction().myProperty; // myFunction has no properties
However, this will work:
function myFunction(){
this.myProperty = "Am I an object!";
}
var myFunctionVar = new myFunction();
myFunctionVar.myProperty;
Is this just a matter of semantics... in the whole of the programming world, when does an object really become an object, and how does that map to JavaScript?
There is nothing magical about functions and constructors. All objects in JavaScript are … well, objects. But some objects are more special than the others: namely built-in objects. The difference lies mostly in following aspects:
General treatment of objects. Examples:
Numbers and Strings are immutable (⇒ constants). No methods are defined to change them internally — new objects are always produced as the result. While they have some innate methods, you cannot change them, or add new methods. Any attempts to do so will be ignored.
null and undefined are special objects. Any attempt to use a method on these objects or define new methods causes an exception.
Applicable operators. JavaScript doesn't allow to (re)define operators, so we stuck with what's available.
Numbers have a special way with arithmetic operators: +, -, *, /.
Strings have a special way to handle the concatenation operator: +.
Functions have a special way to handle the "call" operator: (), and the new operator. The latter has the innate knowledge on how to use the prototype property of the constructor, construct an object with proper internal links to the prototype, and call the constructor function on it setting up this correctly.
If you look into the ECMAScript standard (PDF) you will see that all these "extra" functionality is defined as methods and properties, but many of them are not available to programmers directly. Some of them will be exposed in the new revision of the standard ES3.1 (draft as of 15 Dec 2008: PDF). One property (__proto__) is already exposed in Firefox.
Now we can answer your question directly. Yes, a function object has properties, and we can add/remove them at will:
var fun = function(){/* ... */};
fun.foo = 2;
console.log(fun.foo); // 2
fun.bar = "Ha!";
console.log(fun.bar); // Ha!
It really doesn't matter what the function actually does — it never comes to play because we don't call it! Now let's define it:
fun = function(){ this.life = 42; };
By itself it is not a constructor, it is a function that operates on its context. And we can easily provide it:
var context = {ford: "perfect"};
// now let's call our function on our context
fun.call(context);
// it didn't create new object, it modified the context:
console.log(context.ford); // perfect
console.log(context.life); // 42
console.log(context instanceof fun); // false
As you can see it added one more property to the already existing object.
In order to use our function as a constructor we have to use the new operator:
var baz = new fun();
// new empty object was created, and fun() was executed on it:
console.log(baz.life); // 42
console.log(baz instanceof fun); // true
As you can see new made our function a constructor. Following actions were done by new:
New empty object ({}) was created.
Its internal prototype property was set to fun.prototype. In our case it will be an empty object ({}) because we didn't modify it in any way.
fun() was called with this new object as a context.
It is up to our function to modify the new object. Commonly it sets up properties of the object, but it can do whatever it likes.
Fun trivia:
Because the constructor is just an object we can calculate it:
var A = function(val){ this.a = val; };
var B = function(val){ this.b = val; };
var C = function(flag){ return flag ? A : B; };
// now let's create an object:
var x = new (C(true))(42);
// what kind of object is that?
console.log(x instanceof C); // false
console.log(x instanceof B); // false
console.log(x instanceof A); // true
// it is of A
// let's inspect it
console.log(x.a); // 42
console.log(x.b); // undefined
// now let's create another object:
var y = new (C(false))(33);
// what kind of object is that?
console.log(y instanceof C); // false
console.log(y instanceof B); // true
console.log(y instanceof A); // false
// it is of B
// let's inspect it
console.log(y.a); // undefined
console.log(y.b); // 33
// cool, heh?
Constructor can return a value overriding the newly created object:
var A = function(flag){
if(flag){
// let's return something completely different
return {ford: "perfect"};
}
// let's modify the object
this.life = 42;
};
// now let's create two objects:
var x = new A(false);
var y = new A(true);
// let's inspect x
console.log(x instanceof A); // true
console.log(x.ford); // undefined
console.log(x.life); // 42
// let's inspect y
console.log(y instanceof A); // false
console.log(y.ford); // perfect
console.log(y.life); // undefined
As you can see x is of A with the prototype and all, while y is our "naked" object we returned from the constructor.
Your understanding is wrong:
myFunction().myProperty; // myFunction has no properties
The reason it does not work is because ".myProperty" is applied to the returned value of "myFunction()", not to the object "myFunction". To wit:
$ js
js> function a() { this.b=1;return {b: 2};}
js> a().b
2
js>
Remember, "()" is an operator. "myFunction" is not the same as "myFunction()". You don't need a "return" when instanciang with new:
js> function a() { this.b=1;}
js> d = new a();
[object Object]
js> d.b;
1
To answer your specific question, technically functions are always objects.
For instance, you can always do this:
function foo(){
return 0;
}
foo.bar = 1;
alert(foo.bar); // shows "1"
Javascript functions behave somewhat like classes in other OOP languages when they make use of the this pointer. They can be instantiated as objects with the new keyword:
function Foo(){
this.bar = 1;
}
var foo = new Foo();
alert(foo.bar); // shows "1"
Now this mapping from other OOP languages to Javascript will fail quickly. For instance, there is actually no such thing as classes in Javascript - objects use a prototype chain for inheritance instead.
if you're going to do any sort of significant programming in Javascript, I highly recommend Javascript: The Good Parts by Crockford, that guy you emailed.
The "global" scope of Javascript (at least in a browser) is the window object.
This means that when you do this.myProperty = "foo" and call the function as plain myFunction() you're actually setting window.myProperty = "foo"
The second point with myFunction().myProperty is that here you're looking at the return value of myFunction(), so naturally that won't have any properties as it returns null.
What you're thinking of is this:
function myFunction()
{
myFunction.myProperty = "foo";
}
myFunction();
alert(myFunction.myProperty); // Alerts foo as expected
This is (almost) the same as
var myFunction = new Function('myFunction.myProperty = "foo";');
myFunction();
When you use it in the new context, then the "return value" is your new object and the "this" pointer changes to be your new object, so this works as you expect.
Indeed, Functions are 'first class citizens': they are an Object.
Every object has a Prototype, but only a function's prototype can be referenced directly. When new is called with a function object as argument, a new object is constructed using the function object's prototype as prototype, and this is set to the new object before the function is entered.
So you could call every function a Constructor, even if it leaves this alone.
There are very good tutorials out there on constructors, prototypes etc... Personally I learned a lot from Object Oriented Programming in JavaScript. It shows the equivalence of a function which 'inherits' its prototype, but uses this to fill in a new object's properties, and a function object that uses a specific prototype:
function newA() { this.prop1 = "one"; } // constructs a function object called newA
function newA_Too() {} // constructs a function object called newA_Too
newA_Too.prototype.prop1 = "one";
var A1 = new newA();
var A2 = new newA_Too();
// here A1 equals A2.
First, JavaScript doesn't behave the same way about objects as C++/Java does, so you need to throw those sorts of ideas out of the window to be able to understand how javascript works.
When this line executes:
var myFunctionVar = new myFunction();
then the this inside of myFunction() refers to this new object you are creating - myFunctionVar. Thus this line of code:
this.myProperty = "Am I an object!";
essentially has the result of
myFunctionVar.myProperty = "Am I an object!";
It might help you to take a look at some documentation on the new operator. In JS, the new operator essentially allows you to create an object out of a function - any plain old function. There is nothing special about the function that you use with the new operator that marks it as a constructor, as it would be in C++ or Java. As the documentation says:
Creating a user-defined object type requires two steps:
Define the object type by writing a function.
Create an instance of the object with new.
So what you have done with the code
function myFunction(){
this.myProperty = "Am I an object!";
}
is to create a function that would be useful as a constructor. The reason why the code myFunction.myProperty fails is that there is no reference named myFunction.
JavaScript is based on the ECMA script. Its specification uses the prototyping model for it to be OOP. How ever, ECMA script does not enforce strict data types.
The object needs to be instantiated for the same reason that ECMA script requires a 'new' call which will allocate memory for the property, Otherwise it will remain a function and you can call it if you like, in which case, the property will initialize and then be destroyed when the function ends.
Only when you instantiate with the new keyword does the function act as a constructor.
The result is an object that can use the "this" keyword to access member properties. The this keyword in the method does not make any sense when the function is used any other way.