I stumbled upon a pattern in JavaScript that I refer to as a `nested literal'. It works because you can have self invoking function literals as arguments of self invoking function literals.
A self invoking function literal is a function that immediately evaluates itself, like so:
(function(arg1, arg2) { return arg1 + arg2; }) (1, 2);
This is equivalent to writing
3;
One advantage of using such self invoking function literals is that its code is strictly top-down, which makes it very easy to understand. Consider
document.write(
(function(
factorial,
square
) {
return factorial(square(3));
} (
function f(x) {
if (x <= 1) return 1;
else return x * f(x - 1);
},
function f(x) {
return x*x;
}
))
);
Assuming you recognize the argument of document.write() as a self invoking function literal, you don't have to be very smart to understand that this program writes the factorial of the square of three to a page, and to understand how the factorial and square functions are implemented. The program reads intuitively as "in the document, write the factorial of the square of 3, where factorial is ... and square is ... .".
What's more, there is nothing from stopping you of making one of the arguments of a self invoking function literal such a function literal itself. For example:
(function(arg1, arg2) { return arg1 + arg2 }) (
1,
(function(arg1, arg2) { return arg1 + arg2 })(2, 3)
);
This is equivalent to writing
6;
This nesting can go on and on, allowing you to make extremely complex literals that are very simple to understand. Consider the final program:
document.write(
/* text = */ (
(function(
title,
section1,
section2,
section3
) {
return ('<h3>' + title + '</h3>' +
section1 +
section2 +
section3
);
} (
/* title = */ (
'Nested Literals in JavaScript'
),
/* section1 = */ (
(function(
title_section1,
paragraph1_section1,
paragraph2_section1
) {
return ('<h4>' + title_section1 + '</h4>' +
'<p>' + paragraph1_section1 + '</p>' +
'<p>' + paragraph2_section1 + '</p>'
);
} (
/* title_section1 = */ (
'Nested Literals'
),
/* paragraph1_section1 = */ (
"JavaScript allows nested literals through its self invocating function literals. This is because self invocating function literals take literals as arguments. Therefore, a self invocating function literal can take an argument that is a self invocating function literal that can take an argument that is ... ."
),
/* paragraph2_section1 = */ (
"This is cool! for it allows arbitrarily complex literals. This program consists out of a single call to document.write(), its argument being relatively complex."
)
))
),
/* section2 = */ (
(function(
title_section2,
paragraph1_section2,
paragraph2_section2,
paragraph3_section2
) {
return ('<h4>' + title_section2 + '</h4>' +
'<p>' + paragraph1_section2 + '</p>' +
'<p>' + paragraph2_section2 + '</p>' +
'<p>' + paragraph3_section2 + '</p>'
);
} (
/* title_section2 = */ (
'Top-Down Coding'
),
/* paragraph1_section2 = */ (
"Using nested literals, your code can become very readable. Reading the code from top to bottom you will get to understand the structure top-down, which is how we (at least I) like it."
),
/* paragraph2_section2 = */ (
"This code is an example of this. What it does is probably obvious on your first read. If not, then it is probably because you are not familiar enough with self invocating function literals, yet."
),
/* paragraph3_section2 = */ (
"And not only does it makes programs easy to read, it makes them easy to write."
)
))
),
/* section3 = */ (
(function(
title_section3,
paragraph1_section3,
paragraph2_section3,
paragraph3_section3
) {
return ('<h4>' + title_section3 + '</h4>' +
'<p>' + paragraph1_section3 + '</p>' +
'<p>' + paragraph2_section3 + '</p>' +
'<p>' + paragraph3_section3 + '</p>'
);
} (
/* title_section3 = */ (
'Local Variables Only'
),
/* paragraph1_section3 = */ (
"Because everything is literal, or anonymous, no assignments are made. This keeps the global scope completely clean."
),
/* paragraph2_section3 = */ (
"Also, arguments to a self invocating function literal are outside the scope of the body of the self invocating function literal. This makes their scopes completely separated. Even though their behaviour is nested, their scopes are not."
),
/* paragraph3_section3 = */ (
"This puts nested literals in contrast to nested functions, which allow their behaviour to get tangled up with the variables of the function in which they are nested."
)
开发者_如何学C ))
)
))
)
);
I think it is obvious what it does. You can run it by clicking in text field of your adress bar, typing 'javascript:', pasting the above source code and pressing enter.
What I am unsure about is how efficient the use of nested literals is. I wonder if you would run into any trouble if you would take this to the extreme. I am wondering if anyone knows.
Anyway, I just wanted to share this, perhaps hear what you think.
Regards, Pieter Jan
All I would say is: Make sure your code is readable. Don't do something like this just because it's cool that you can do it. Do it if it makes your code more readable. Which sometimes it does, and sometimes it definitely doesn't.
I can see at least two major reasons why it's not a good idea
You code becomes slower - every time you do a function call in javascript, a new callstack has to be initialized amongst other things, it is a massive overhead if what the function does is trivial and only needs to happen once, this of instance is why doing a normal loop is so much faster than using convenience methods like jQuerys .each, that calls a function on every iteration.
If you need to do the same thing twice or more, do use functions, but give them names and reference them, that way you code will be infinitely easier to maintain, and named functions also gives you the benefit of being profileable - try to profile a lot of javascript littered with anonymous functions is like clapping with one hand.
精彩评论