By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,847 Members | 3,231 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,847 IT Pros & Developers. It's quick & easy.

FunctionExpression's and memory consumptions

P: n/a
There's a common pattern of "forking" a returning function as in the
following example:

function bind(fn, context) {
var args = Array.prototype.slice.call(arguments, 2);
if (args.length) {
return function() {
fn.apply(context, args);
}
}
return function() {
return fn.call(context);
}
}

The runtime speed benefits are obvious, but I've been told that there
is an increased memory consumption in such cases. Are there 2 Function
objects created when `bind` is being called? I assume that's not the
case, since those are not FunctionDeclaration's, but rather
FunctionExpression's (and so they should not be evaluated foremost
when execution context is entered). Are FunctionExpression's contained
within blocks that are never evaluated create Function objects? Does
it make a difference if FunctionExpression is contained within a
`return` clause?

I can't find relevant parts in the specification and would appreciate
any insights on this matter.

--
kangax
Oct 27 '08 #1
Share this Question
Share on Google+
19 Replies


P: n/a
kangax wrote:
There's a common pattern of "forking" a returning function as in the
following example:

function bind(fn, context) {
var args = Array.prototype.slice.call(arguments, 2);
if (args.length) {
return function() {
fn.apply(context, args);
}
}
return function() {
return fn.call(context);
}
}

The runtime speed benefits are obvious, but I've been told that there
is an increased memory consumption in such cases. Are there 2 Function
objects created when `bind` is being called? I assume that's not the
case, since those are not FunctionDeclaration's, but rather
FunctionExpression's (and so they should not be evaluated foremost
when execution context is entered). Are FunctionExpression's contained
within blocks that are never evaluated create Function objects? Does
it make a difference if FunctionExpression is contained within a
`return` clause?
Unreached expressions should have no effect. We can see a call expression:-

function unreachableExpression() {
if(true) return;
alert("Panic!!! I did not feature-test alert!");
}

And a return statement would also have no effect:-

function unreachableStatement() {
if(true) return true;
return false;
}

Each time that bind function is called, a new function is created, not
two. If arguments.length were 0, the second function expression would be
returned, but would always err because fn would be undefined. You
probably meant to check "if(arguments.length 2)".

function f(){
alert(this.type);
}

var e = bind(f, { sound: "elephant" });

The second function does not need the args property, so creating an
array would be unnecessary.

function bind(fn, context) {
var args;
if (arguments.length 2) {
args = Array.prototype.slice.call(arguments, 2);
return function() {
fn.apply(context, args);
}
}
return function() {
return fn.call(context);
}
}

Garrett
--
comp.lang.javascript FAQ <URL: http://jibbering.com/faq/ >
Oct 27 '08 #2

P: n/a
On Oct 26, 9:42*pm, kangax <kan...@gmail.comwrote:
There's a common pattern of "forking" a returning function as in the
following example:

function bind(fn, context) {
* var args = Array.prototype.slice.call(arguments, 2);
* if (args.length) {
* * return function() {
* * * fn.apply(context, args);
* * }
* }
* return function() {
* * return fn.call(context);
* }

}

The runtime speed benefits are obvious, but I've been told that there
is an increased memory consumption in such cases. Are there 2 Function
objects created when `bind` is being called? I assume that's not the
case, since those are not FunctionDeclaration's, but rather
FunctionExpression's (and so they should not be evaluated foremost
when execution context is entered). Are FunctionExpression's contained
within blocks that are never evaluated create Function objects? Does
No.
it make a difference if FunctionExpression is contained within a
`return` clause?
What is a return clause?
Oct 28 '08 #3

P: n/a
On Oct 26, 10:49 pm, dhtml <dhtmlkitc...@gmail.comwrote:
kangax wrote:
There's a common pattern of "forking" a returning function as in the
following example:
function bind(fn, context) {
var args = Array.prototype.slice.call(arguments, 2);
if (args.length) {
return function() {
fn.apply(context, args);
}
}
return function() {
return fn.call(context);
}
}
The runtime speed benefits are obvious, but I've been told that there
is an increased memory consumption in such cases. Are there 2 Function
objects created when `bind` is being called? I assume that's not the
case, since those are not FunctionDeclaration's, but rather
FunctionExpression's (and so they should not be evaluated foremost
when execution context is entered). Are FunctionExpression's contained
within blocks that are never evaluated create Function objects? Does
it make a difference if FunctionExpression is contained within a
`return` clause?

Unreached expressions should have no effect. We can see a call expression:-

function unreachableExpression() {
if(true) return;
alert("Panic!!! I did not feature-test alert!");

}

And a return statement would also have no effect:-

function unreachableStatement() {
if(true) return true;
return false;

}

Each time that bind function is called, a new function is created, not
two. If arguments.length were 0, the second function expression would be
returned, but would always err because fn would be undefined. You
probably meant to check "if(arguments.length 2)".

function f(){
alert(this.type);

}

var e = bind(f, { sound: "elephant" });

The second function does not need the args property, so creating an
array would be unnecessary.

function bind(fn, context) {
var args;
if (arguments.length 2) {
args = Array.prototype.slice.call(arguments, 2);
return function() {
fn.apply(context, args);
}
}
return function() {
return fn.call(context);
}

}
Thanks, Garrett.
That makes much sense.

So, as far as I understand, function expression in "unreached" block
is no different than any other expression in "unreached" block (in a
sense that it shouldn't be executed and so shouldn't allocate any
memory). Does spec actually define such behavior (object
initialization) or is it left up to an implementation?
>
Garrett

--
comp.lang.javascript FAQ <URL:http://jibbering.com/faq/>
--
kangax
Oct 28 '08 #4

P: n/a
On Oct 27, 2:42*am, kangax <kan...@gmail.comwrote:
There's a common pattern of "forking" a returning function as in the
following example:

function bind(fn, context) {
* var args = Array.prototype.slice.call(arguments, 2);
* if (args.length) {
* * return function() {
* * * fn.apply(context, args);
* * }
* }
* return function() {
* * return fn.call(context);
* }

}

The runtime speed benefits are obvious, but I've been told that there
is an increased memory consumption in such cases. Are there 2 Function
objects created when `bind` is being called? I assume that's not the
case, since those are not FunctionDeclaration's, but rather
FunctionExpression's (and so they should not be evaluated foremost
when execution context is entered). Are FunctionExpression's contained
within blocks that are never evaluated create Function objects? Does
it make a difference if FunctionExpression is contained within a
`return` clause?

I can't find relevant parts in the specification and would appreciate
any insights on this matter.
Note that that creates both a function and a closure: the context of
"bind" that is saved in the closure occupies memory as well. But only
the function that is returned is created.

--
Jorge.
Oct 28 '08 #5

P: n/a
On Oct 28, 12:25*am, David Mark <dmark.cins...@gmail.comwrote:
On Oct 26, 9:42*pm, kangax <kan...@gmail.comwrote:
[snip]
it make a difference if FunctionExpression is contained within a
`return` clause?

What is a return clause?
Sorry, I meant to say - return statement.

--
kangax

Oct 28 '08 #6

P: n/a
On Oct 28, 7:49*am, kangax <kan...@gmail.comwrote:
On Oct 26, 10:49 pm, dhtml <dhtmlkitc...@gmail.comwrote:
kangax wrote:
There's a common pattern of "forking" a returning function as in the
following example:
function bind(fn, context) {
* var args = Array.prototype.slice.call(arguments, 2);
* if (args.length) {
* * return function() {
* * * fn.apply(context, args);
* * }
* }
* return function() {
* * return fn.call(context);
* }
}
The runtime speed benefits are obvious, but I've been told that there
is an increased memory consumption in such cases. Are there 2 Function
objects created when `bind` is being called? I assume that's not the
case, since those are not FunctionDeclaration's, but rather
FunctionExpression's (and so they should not be evaluated foremost
when execution context is entered). Are FunctionExpression's contained
within blocks that are never evaluated create Function objects? Does
it make a difference if FunctionExpression is contained within a
`return` clause?
Unreached expressions should have no effect. We can see a call expression:-
function unreachableExpression() {
* *if(true) return;
* *alert("Panic!!! I did not feature-test alert!");
}
And a return statement would also have no effect:-
function unreachableStatement() {
* *if(true) return true;
* *return false;
}
Each time that bind function is called, a new function is created, not
two. If arguments.length were 0, the second function expression would be
returned, but would always err because fn would be undefined. You
probably meant to check "if(arguments.length 2)".
function f(){
* *alert(this.type);
}
var e = bind(f, { sound: "elephant" });
The second function does not need the args property, so creating an
array would be unnecessary.
function bind(fn, context) {
* *var args;
* *if (arguments.length 2) {
* * *args = Array.prototype.slice.call(arguments, 2);
* * *return function() {
* * * *fn.apply(context, args);
* * *}
* *}
* *return function() {
* * *return fn.call(context);
* *}
}

Thanks, Garrett.
That makes much sense.

So, as far as I understand, function expression in "unreached" block
is no different than any other expression in "unreached" block (in a
sense that it shouldn't be executed and so shouldn't allocate any
memory). Does spec actually define such behavior (object
initialization) or is it left up to an implementation?
Yes, it is defined in the specs, which you should be read at least
once.
Oct 28 '08 #7

P: n/a
On 2008-10-30 06:54, dhtml wrote:
I see that "The Good Parts" calls "FunctionDeclaration" a "function
Statement". This is completely misleading and I've been seeing posts
using this wrong terminology a lot lately.
This isn't just coming from The Good Parts.
Mozilla uses it in their docs, too:
http://www.google.com/search?q=site:...n+statement%22

Microsoft use it as well...
http://msdn.microsoft.com/en-us/library/4t2k5yhw.aspx

....as does Flanagan in the "Definitive Guide":
http://preview.tinyurl.com/6yytpv
This is wrong terminology. What he is calling a function Statement is
really a FunctionDeclaration. A FunctionDeclaration is not a
Statement. It cannot appear where statements do.
Most current implementations allow nesting:

if (blah) {
function blimm () {
....
}
}

Mozilla treats this as a function expression, not a function
declaration, meaning that it will not be evaluated unless blah is true.
Only source elements will be treated as function declarations.
An implementation that evaluated the function on either pass would
seem to be doing whatever is the opposite of an optimization.
Pessimization :-)
- Conrad
Oct 30 '08 #8

P: n/a
On Oct 30, 11:19 am, Conrad Lender wrote:
On 2008-10-30 06:54, dhtml wrote:
>I see that "The Good Parts" calls "FunctionDeclaration" a
"function Statement". This is completely misleading and
I've been seeing posts using this wrong terminology a
lot lately.

This isn't just coming from The Good Parts.
Mozilla uses it in their docs, too:
<snip>
Microsoft use it as well...
<snip>
...as does Flanagan in the "Definitive Guide":
<snip>

Poor terminology choices are normal for both Flanagan and Microsoft,
and Mozilla documentation is still a little short of being good
(though certainly much improved over recent years). However, much
writing on the subject of javascript is (where it is not actually
inaccurate) aimed at audiences who have a great deal to learn before
they appreciate the subtleties; where moving in the direction of
understanding might be seen more productive than laying out the gory
details in full.

<snip>
Most current implementations allow nesting:

if (blah) {
function blimm () {
....
}

}

Mozilla treats this as a function expression,
Not it does not.
not a function declaration, meaning that it will not be
evaluated unless blah is true.
With a function expression with optional Identifier (which is what the
above would be if it were a function expression) the resulting
function object can only be referenced using that Identifier from
inside the body of the function (all else being equal), because an new
object is added to the new function object's [[Scope]] and the
Identifier used to create a named property of that object to refer to
the function. Thus - blimm - is out of scope in the surrounding code,
if the code were a function expression.

In Mozilla browsers the function does become available using the
Identifier - blimm - in the containing scope, thus this is not a
function expression. In fact it is a function statement; a syntax
extension that is capable of allowing the conditional creation of a
function because being a Statement it can be evaluative inside a
block.

Mozilla also has FunctionDeclarations (which create function objects
during variable instantiation) and FunctionExpressions (which create
function object when evaluated, and do follow the ECMAScript rules
regarding optional Identifiers). The Mozilla docs might blur the
distinction but it exists regardless.

IE browsers also process the above code successfully (or at lest
without erroring) , but they see the function as a FunctionDeclaration
regardless of its 'illegal' context. Thus IE would create a function
object during variable instantiation, and so any surrounding
conditions (the - if(blah){ ... } - in this case) become redundant,
and the last FunctionDeclaration with any given name becomes the only
one available in the scope.

Most browsers (more or less) imitate one of these 'extensions' for
reasons of compatibility. But notations of which they should be
compatible with (JScript or JavaScript(tm)) seem to change. As I
recall (and my memory may not be accurate on this point) Opera had
switched from following JScript to following JavaScript, which Safari
has switched from following JavaScript to following JScript.

Obviously with two distinct interpretations of this code structure,
and minor browsers not necessarily sticking to following one or the
other (plus some related bugs that introduce some more variation)
using this type of code structure is seriously ill-advised. With
results that that may appear to 'work', but maybe only by coincidence
and for the time being. Plus (and most importantly) conditional
creation of function objects is (and always has been) possible using
pure ECMAScript constructs (by assigning the results of evaluating
function expressions to variables declared in the containing scope).

Interestingly the draft ES 3.1 spec is trying to switch
FunctionDeclaration to being a Statement. How that will work out
remains to be seen as the last draft I looked at (the one before the
current draft, which I haven't looked at yet) did not include any
processing or evaluation rules for their function statements (a bit of
an oversight as it makes the draft language non-viable as it stood).
Only source elements will be treated as function declarations.
<snip>

Only function declarations will be treated as function declarations
(in ES 3), Statements are SourceElements.

Richard.
Oct 30 '08 #9

P: n/a
On Oct 30, 1:54*am, dhtml <dhtmlkitc...@gmail.comwrote:
[snip explanation]

Thanks for such thorough explanation.
I'll make sure to read specs better next time.
--
comp.lang.javascript FAQ <URL:http://jibbering.com/faq/>
--
kangax
Oct 30 '08 #10

P: n/a
On 2008-10-30 13:06, Richard Cornford wrote:
>if (blah) {
function blimm () {
....
}

}

Mozilla treats this as a function expression,

Not it does not.
[..]
In Mozilla browsers the function does become available using the
Identifier - blimm - in the containing scope, thus this is not a
function expression. In fact it is a function statement; a syntax
extension that is capable of allowing the conditional creation of a
function because being a Statement it can be evaluative inside a
block.
You're right, what I meant to say was Mozilla "treats it as if it were
a function expression of the form: var blimm = function () {...}".
Although it has the form of a function declaration, no function object
will be created during the variable instantiation phase. Only when the
function "statement" is evaluated will its identifier become available
in the current scope.

Should the term "function statement" be used to specifically refer to
this extension?
IE browsers also process the above code successfully (or at lest
without erroring) , but they see the function as a FunctionDeclaration
regardless of its 'illegal' context.
[...]
Most browsers (more or less) imitate one of these 'extensions' for
reasons of compatibility. But notations of which they should be
compatible with (JScript or JavaScript(tm)) seem to change. As I
recall (and my memory may not be accurate on this point) Opera had
switched from following JScript to following JavaScript, which Safari
has switched from following JavaScript to following JScript.
It appears that only Mozilla doesn't see them as function declarations.
In this example:

function testFD() {
if (true) {
function blimm() { alert("true"); }
} else {
function blimm() { alert("false"); }
}
blimm();
}

Opera 9.61 alerts "false", same as IE and Safari. Konqueror (old 3.5.2
version) doesn't see blimm at all.
[..] using this type of code structure is seriously ill-advised.
Of course; I fully agree.
Interestingly the draft ES 3.1 spec is trying to switch
FunctionDeclaration to being a Statement.
I didn't know that. Could make things... interesting.
>Only source elements will be treated as function declarations.
<snip>

Only function declarations will be treated as function declarations
(in ES 3), Statements are SourceElements.
Not all Statements are SourceElements. Mozilla will not treat a
"function declaration in a block" as a FunctionDeclaration, because
it's nested, and thus not a SourceElement.

http://preview.tinyurl.com/mdc-function-expression
(a little further down)
- Conrad
Oct 30 '08 #11

P: n/a
Conrad Lender <cr******@yahoo.comwrites:
You're right, what I meant to say was Mozilla "treats it as if it were
a function expression of the form: var blimm = function () {...}".
Not exectly.
Although it has the form of a function declaration, no function object
will be created during the variable instantiation phase. Only when the
function "statement" is evaluated will its identifier become available
in the current scope.
Exactly. A "var" declaration would also declare the "blimm" variable
globally in the scope. As you say, that's not what happens. Mozilla
only declares blimm if you actually execute the function statement. It
really is different from both "var" and "function" declarations, since
it adds a variable to the scope AFTER it was initially created and
populated by the declarations.

/L
--
Lasse Reichstein Holst Nielsen
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Oct 31 '08 #12

P: n/a
On Oct 30, 10:49*pm, Conrad Lender <crlen...@yahoo.comwrote:
>
You're right, what I meant to say was Mozilla "treats it as if it were
a function expression of the form: var blimm = function () {...}".
Although it has the form of a function declaration, no function object
will be created during the variable instantiation phase. Only when the
function "statement" is evaluated will its identifier become available
in the current scope.
No no it's not so. Any function declaration inside an inner block is
considered an error and ignored (in Mozillas). See this thread:

http://groups.google.com/group/comp....9e1428f1e1990b

--
Jorge.
Oct 31 '08 #13

P: n/a
On 2008-10-31 08:21, Jorge wrote:
No no it's not so. Any function declaration inside an inner block is
considered an error and ignored (in Mozillas).
They're not ignored. Try the function in my previous post and see if you
get an alert.
See this thread:

http://groups.google.com/group/comp....9e1428f1e1990b
I'm not sure how this is relevant - nothing in that thread suggests that
Mozilla discards function declarations in a block.
- Conrad
Nov 1 '08 #14

P: n/a
On 2008-10-31 06:55, Lasse Reichstein Nielsen wrote:
>Although it has the form of a function declaration, no function object
will be created during the variable instantiation phase. Only when the
function "statement" is evaluated will its identifier become available
in the current scope.

Exactly. A "var" declaration would also declare the "blimm" variable
globally in the scope. As you say, that's not what happens. Mozilla
only declares blimm if you actually execute the function statement. It
really is different from both "var" and "function" declarations, since
it adds a variable to the scope AFTER it was initially created and
populated by the declarations.
The difference between "var x = function ..." and "function x ..." can
be shown in an example:

function testFD1() {
print(delete blimm); // =true (blimm not declared)
if (1) {
function blimm() { alert("true"); }
}
}

function testFD2() {
print(delete blimm); // =false (blimm has DontDelete attribute)
if (1) {
var blimm = function() { alert("true"); }
}
}

Out of curiosity, does this difference have any practical consequences
other than the return value of 'delete'?
- Conrad
Nov 1 '08 #15

P: n/a
On Nov 1, 2:24*am, Conrad Lender <crlen...@yahoo.comwrote:
On 2008-10-31 08:21, Jorge wrote:
No no it's not so. Any function declaration inside an inner block is
considered an error and ignored (in Mozillas).

They're not ignored. Try the function in my previous post and see if you
get an alert.
(...)
I'm not sure how this is relevant - nothing in that thread suggests that
Mozilla discards function declarations in a block.
Try this:

<script>
window.onload= function () {
function foo () { alert('outer'); }
if (true) {
function foo () { alert('inner'); }
}
foo();
};
</script>

Mozillas: -outer
Everywhere else: -inner

--
Jorge.
Nov 1 '08 #16

P: n/a
On Nov 1, 9:42*am, Jorge <jo...@jorgechamorro.comwrote:
On Nov 1, 2:24*am, Conrad Lender <crlen...@yahoo.comwrote:
On 2008-10-31 08:21, Jorge wrote:
No no it's not so. Any function declaration inside an inner block is
considered an error and ignored (in Mozillas).
They're not ignored. Try the function in my previous post and see if you
get an alert.
(...)
I'm not sure how this is relevant - nothing in that thread suggests that
Mozilla discards function declarations in a block.

Try this:

<script>
window.onload= function () {
* function foo () { alert('outer'); }
* if (true) {
* * function foo () { alert('inner'); }
* }
* foo();};

</script>

Mozillas: -outer
Everywhere else: -inner
Note that changing if (true) to if (false) doesn't make any
difference.

--
Jorge.
Nov 1 '08 #17

P: n/a
On Nov 1, 2:24*am, Conrad Lender <crlen...@yahoo.comwrote:
On 2008-10-31 08:21, Jorge wrote:
No no it's not so. Any function declaration inside an inner block is
considered an error and ignored (in Mozillas).

They're not ignored. Try the function in my previous post and see if you
get an alert.
(...)
I'm not sure how this is relevant - nothing in that thread suggests that
Mozilla discards function declarations in a block.
Try this:

<script>
window.onload= function () {
function foo () { alert('outer'); }
if (true) {
function foo () { alert('inner'); }
}
foo();
};
</script>

Mozillas: -outer
Everywhere else: -inner

--
Jorge.
Nov 1 '08 #18

P: n/a
On Nov 1, 9:42*am, Jorge <jo...@jorgechamorro.comwrote:
On Nov 1, 2:24*am, Conrad Lender <crlen...@yahoo.comwrote:
On 2008-10-31 08:21, Jorge wrote:
No no it's not so. Any function declaration inside an inner block is
considered an error and ignored (in Mozillas).
They're not ignored. Try the function in my previous post and see if you
get an alert.
(...)
I'm not sure how this is relevant - nothing in that thread suggests that
Mozilla discards function declarations in a block.

Try this:

<script>
window.onload= function () {
* function foo () { alert('outer'); }
* if (true) {
* * function foo () { alert('inner'); }
* }
* foo();};

</script>

Mozillas: -outer
Everywhere else: -inner
Note that changing if (true) to if (false) doesn't make any
difference.

--
Jorge.
Nov 1 '08 #19

P: n/a
On Nov 1, 3:55*am, Jorge <jo...@jorgechamorro.comwrote:
On Nov 1, 9:42*am, Jorge <jo...@jorgechamorro.comwrote:
[...]
Try this:
<script>
window.onload= function () {
* function foo () { alert('outer'); }
* if (true) {
* * function foo () { alert('inner'); }
* }
* foo();};
</script>
Mozillas: -outer
Everywhere else: -inner

Note that changing if (true) to if (false) doesn't make any
difference.
It's interesting to observe FunctionStatement's (if we can call it
that way) behavior. From what I can see:

1) FunctionStatement's do not overwrite variables declared via
FunctionDeclaration's
2) FunctionStatement's are not declared when enclosing block is being
entered (but only when a statement is being evaluated)
3) Once declared, FunctionStatement's are available to the entire
function scope (enclosing one), even outside of an actual block (in
which it was evaluated).
4) One FunctionStatement can overwrite another FunctionStatement with
the same identifier.

Tested in: Firefox 3.0.3; Mac OS X 10.5

function write(s) {
document.write(s + '<br>');
}

(function(){

function f(){ return 'outer' };

if (true) {
write(
'typeof g (before FunctionStatement) ' +
(typeof g)
); // undefined

function g(){ return 'inner' };

write(
'typeof g (after FunctionStatement) ' +
(typeof g)
); // function

write('g() ' + g()); // inner

write('delete g ' + (delete g)); // false
write(
'typeof g (after deletion) ' +
(typeof g)
); // function

function g(){ return 'inner2' }
write(
'g() (second FunctionStatement with the same identifier) ' +
g()
); // inner2

function f(){ return 'inner' }
write(
'f() (after FunctionStatement named as '+
'FunctionDeclaration outside of enclosing block) ' +
f()
); // outer
}

write(
'typeof g (outside of block in which it was declared) ' +
(typeof g)
); // function
write(
'g() (outside of block in which it was declared) ' +
g()
); // inner2

})();
>
--
Jorge.
--
kangax
Nov 11 '08 #20

This discussion thread is closed

Replies have been disabled for this discussion.