The following ways of writing a javascript function are equivalent.
Maybe the first one is more clear.
Nevertheless, many programmers prefer the second way.
There are significant difference between the two ways for preferring the second-one?
First way:
Class.prototype.fn = function () {
var obj = {
…
};
return obj;
};
Second way:
Class.prototype.fn = function () {
return {
.........
};
};
Unless you need to perform an operation on obj after creating it via the literal, there's no difference and it's just a subjective style preference. (Note that said use could be in the code, or during debugging; more below.)
So for example, there's a real practical difference here:
Class.prototype.fn = function () {
var obj = {
subordinate: {
foo: function() {
if (obj.flag) {
doOneThing();
}
else {
doSomethingElse();
}
}
}
};
return obj;
};
There, you need the name, so that obj.subordinate.foo() works. (Not that I'd advocate doing this, but it's an example of when there's an objective rather than subjective distinction.) But barring needing to use it after initialization and before return, it's just a subjective thing.
Of course, that use need not necessarily be in the code. The form with the obj variable can be more useful when debugging, if you need to inspect what you're returning before you return it.
Perhaps going a bit off-piste here, but I think it's related: In contrast to the examples in your question, there's a real, practical, tangible difference between this:
Class.prototype.foo = function () {
…
};
Class.prototype.bar = function () {
…
};
and this:
(function() {
function Class_foo() {
…
}
function Class_bar() {
…
}
Class.prototype.foo = Class_foo;
Class.prototype.bar = Class_bar;
})();
...that difference being that in the former, the functions have no names (the properties referring to them do, but not the functions themselves). In the latter case, the functions have real names, which help your tools help you by showing you names in call stacks, lists of breakpoints, etc.
Related
Here's an example of a situation where a simple JS loop does not behave as expected, because of the loop variable not being in a separate scope.
The solution often presented is to construct an unpleasant-looking bit of loop code that looks like this:
for (var i in obj) {
(function() {
... obj[i] ...
// this new shadowed i here is now no longer getting changed by for loop
})(i);
}
My question is, could this be improved upon? Could I use this:
Object.prototype.each = function (f) {
for (var i in this) {
f(i,this[i]);
}
};
// leading to this somewhat more straightforward invocation
obj.each(
function(i,v) {
... v ...
// alternatively, v is identical to
... obj[i] ...
}
);
when I ascertain that I need a "scoped loop"? It is somewhat cleaner looking and should have similar performance to the regular for-loop (since it uses it the same way).
Update: It seems that doing things with Object.prototype is a huge no-no because it breaks pretty much everything.
Here is a less intrusive implementation:
function each (obj,f) {
for (var i in obj) {
f(i,obj[i]);
}
}
The invocation changes very slightly to
each(obj,
function(i,v) {
... v ...
}
);
So I guess I've answered my own question, if jQuery does it this way, can't really go wrong. Any issues I've overlooked though would warrant an answer.
Your answer pretty much covers it, but I think a change in your original loop is worth noting as it makes it reasonable to use a normal for loop when the each() function isn't handy, for whatever reason.
Update: Changed to use an example that's similar to the example referenced by the question to compare the different approaches. The example had to be adjusted because the each() function requires a populated array to iterate over.
Assuming the following setup:
var vals = ['a', 'b', 'c', 'd'],
max = vals.length,
closures = [],
i;
Using the example from the question, the original loop ends up creating 2n functions (where n is the number of iterations) because two functions are created during each iteration:
for (i = 0; i < max; i++) {
closures[i] = (function(idx, val) { // 1st - factoryFn - captures the values as arguments
return function() { // 2nd - alertFn - uses the arguments instead
alert(idx + ' -> ' + val); // of the variables
};
})(i, vals[i]);
}
This can be reduced to creating only n + 1 functions by creating the factory function once, before the loop is started, and then reusing it:
var factoryFn = function(idx, val) {
return function() {
alert(idx + ' -> ' + val);
};
};
for (i = 0; i < max; i++) {
closures[i] = factoryFn(i, vals[i]);
}
This is nearly equivalent to how the each() function might be used in this situation, which would also result in a total of n + 1 functions created. The factory function is created once and passed immediately as an argument to each().
each(vals, function(idx, val) {
closures[idx] = function() {
alert(idx + ' -> ' + val);
};
});
FWIW, I think a benefit to using each() is the code is a bit shorter and creating the factory function right as it's passed into the each() function clearly illustrates this is its only use. A benefit of the for loop version, IMO, is the code that does the loop is right there so it's nature and behavior is completely transparent while the each() function might be defined in a different file, written by someone else, etc.
Global Scope
When something is global means that it is accessible from anywhere in your code. Take this for example:
var monkey = "Gorilla";
function greetVisitor () {
return alert("Hello dear blog reader!");
}
If that code was being run in a web browser, the function scope would be window, thus making it
available to everything running in that web browser window.
Local Scope
As opposed to the global scope, the local scope is when something is just defined and accessible in a
certain part of the code, like a function. For instance;
function talkDirty () {
var saying = "Oh, you little VB lover, you";
return alert(saying);
}
alert(saying); // Throws an error
If you take a look at the code above, the variable saying is only available within the talkDirty
function. Outside of it it isn’t defined at all. Note of caution: if you were to declare saying without
the var keyword preceding it, it would automatically become a global variable.
What this also means is that if you have nested functions, the inner function will have access to the
containing functions variables and functions:
function saveName (firstName) {
function capitalizeName () {
return firstName.toUpperCase();
}
var capitalized = capitalizeName();
return capitalized;
}
alert(saveName("Robert")); // Returns "ROBERT"
As you just saw, the inner function capitalizeName didn’t need any parameter sent in, but had complete
access to the parameter firstName in the outer saveName function. For clarity, let’s take another
example:
function siblings () {
var siblings = ["John", "Liza", "Peter"];
function siblingCount () {
var siblingsLength = siblings.length;
return siblingsLength;
}
function joinSiblingNames () {
return "I have " + siblingCount() + " siblings:\n\n" + siblings.join("\n");
}
return joinSiblingNames();
}
alert(siblings()); // Outputs "I have 3 siblings: John Liza Peter"
As you just saw, both inner functions have access to the siblings array in the containing function, and
each inner function have access to the other inner functions on the same level (in this case,
joinSiblingNames can access siblingCount). However, the variable siblingsLength in the siblingCount is
only available within that function, i.e. that scope.
I've been building a basic live-evaluation javascript development environment (I call it the WEPL.) over the past few days, and realized it'd be nice to be able to associate error messages to line numbers. Unfortunately, eval() doesn't provide a nice way to do this, that I can find.
The solution I've come up with so far is to transform the source before eval() so that it's a set of nested calls to a wrapper to eval() that records some information before eval, checks to see if the eval succeeds, and then uses that info to output more useful troubleshooting information to the user.
My question is, why might this be a bad idea? What problems do I need to solve to make sure this works well?
An example of the sort of transformation I mean, just to make this concrete.
This
if (cond) {
return foo + bar;
}
else {
return baz + quux;
}
becomes this
if (myEval('cond')) {
return myEval("myEval(\"foo\") + myEval(\"bar\")");
else {
return myEval("myEval(\"baz\") + myEval(\"quux\")");
}
Where I obviously didn't wrap the highest level, though I could've, and the programmatic version would.
This won't work if you want to accept even remotely complex scripts. A few potential problems:
Scope
var i = 1; // global scope
!function() {
var i = 2; // function scope
}();
alert(i); // 1
vs.
myEval('var i = 1;'); // global scope
myEval('!function() {
myEval(\'var i = 2;\'); // eval has global scope, always
}();');
myEval('alert(i);'); // 2
Closures
!function() {
var i = 1; // local to outer function
!function() { // inherits context from outer function
alert(i); // 1
}();
}();
vs.
myEval('!function() {
myEval(\'var i = 1;\'); // local to outer function
myEval(\'!function() { // eval has global scope; myEval inherits from wherever it was defined
myEval(\\\'alert(i);\\\'); // undefined
}();\');
}();');
this
var obj = {
n: 1,
f: function() {
return this.n; // this is the object f is called from
}
}
alert(obj.f()); // 1
vs.
myEval('var obj = {
n: myEval(\'1\'),
f: myEval(\'function() {
return myEval(\\\'this.n\\\'); // this is always the window in eval
}')
}');
myEval('alert(obj.f());'); // undefined
Escape creep
You need to escape every quote, and you need to escape escape signs as well. In code with lots of objects, closures, inner functions etc. this will result in escape signs becoming unmanageable:
!function() {
$(function() {
$('#foo').click(function() {
setTimeout(function() {
$.post('/', function(res) {
log(res);
});
}, 1000);
});
});
}();
(note that this is not a particularly contrived or complicated example, it only involves a delyed action with a callback firing on a certain event)
myEval('!function() {
myEval(\'$(myEval(\\\'function() {
myEval(\\\\\\\'$(\\\\\\\'#foo\\\\\\\').click(myEval(\\\\\\\\\\\\\\\'function() {
myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'setTimeout(myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'function() {
myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'$.post('/', myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'function(res) {
myEval(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'log(res);\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\');
}\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'));\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\');
}\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'), 1000);\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\');
}\\\\\\\\\\\\\\\'));\\\\\\\');
}\\\'));\');
}();');
You can probably see what I am getting at.
I had to do something similar when working on an extension for IE. I ended up creating a global variable called 'lineNumber' and I transformed the code to be more like this:
lineNumber = 1; if (cond) {
lineNumber = 2; return foo + bar;
}
else {
lineNumber = 5; return baz + quux;
}
Of course, I made to make sure I used curly braces around all blocks and had to keep my coding simple enough to avoid confusing my poor lame parser -- but it got me through it.
I would like to update some data with JSON when the user clicks on an object. What I came up with is the following double closure.
var buildGetJSON = function(m,t,p,u) {
return function () {
var buildUpdateParticipants = function(m,t,p) {
return function(data) { updateParticipants(m,t,data,p); };
};
$.getJSON(u, buildUpdateParticipants(m,t,p));
};
};
marker.on("click", buildGetJSON(marker, title, popmsg, url));
It works, but made me wonder if there is a more concise way to put this than writing a closure variable for the two function calls. Any hints?
Yes, the second closure is redundant.
function buildGetJSON(m,t,p,u) {
return function() {
$.getJSON(u, function(data) {
updateParticipants(m,t,data,p);
});
};
}
marker.on("click", buildGetJSON(marker,title,popmsg,url));
If you're only using buildGetJSON once, you can further simplify it by making buildGetJSON anonymous.
marker.on("click", function(m,t,p,u) {return function() {
$.getJSON(u, function(data) {
updateParticipants(m,t,data,p);
});
};}(marker,title,popmsg,url));
Here's another way to do it entirely with anonymous functions. It doesn't collapse into as few lines, but I think it looks a little clearer.
!function(m,t,p,u) {
marker.on("click", function() {
$.getJSON(u, function(data) {
updateParticipants(m,t,data,p);
});
});
}(marker,title,popmsg,url);
Why not simply do this?
marker.on("click", function () {
$.getJSON(url, function (data) {
updateParticipants(marker, title, data, popmsg);
});
});
Looks much more synoptical - at least to me :-)
But be aware: if the variables marker, title etc. can change, and you don't want that, then you need an additional closure. E.g. if you call this for example in loop, and the variable marker (or other variables) changes over the loop! Then you need to enclose your code in another closure within the loop:
for (marker in markers) {
(function (marker) {
// above code
})(marker);
}
Closures are very nice and very strong feature of JavaScript, once you know how to use them. Look at the "The JavaScript Programming Language" videos from Douglas Crockford, they explain it in a great way.
Can I write a function that returns iteself?
I was reading some description on closures - see Example 6 - where a function was returning a function, so you could call func()(); as valid JavaScript.
So I was wondering could a function return itself in such a way that you could chain it to itself indefinitely like this:
func(arg)(other_arg)()(blah);
Using arguments object, callee or caller?
There are 2-3 ways. One is, as you say, is to use arguments.callee. It might be the only way if you're dealing with an anonymous function that's not stored assigned to a variable somewhere (that you know of):
(function() {
return arguments.callee;
})()()()().... ;
The 2nd is to use the function's name
function namedFunc() {
return namedFunc;
}
namedFunc()()()().... ;
And the last one is to use an anonymous function assigned to a variable, but you have to know the variable, so in that case I see no reason, why you can't just give the function a name, and use the method above
var storedFunc = function() {
return storedFunc;
};
storedFunc()()()().... ;
They're all functionally identical, but callee is the simplest.
Edit: And I agree with SLaks; I can't recommend it either
Yes.
Just return arguments.callee;
However, this is likely to result in very confusing code; I do not recommend it.
You can do what you want as following:
// Do definition and execution at the same time.
var someFunction = (function someFunction() {
// do stuff
return someFunction
})();
console.log(someFunction)
arguments.callee is not supported in JavaScript strict mode.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
Even sorter that all the above is:
f=()=>f
There is a simple way to achieve this doing the following:
let intArr = [];
function mul(x){
if(!x){
return intArr.reduce((prev, curr) => prev * curr)
}
intArr.push(x);
return mul;
}
console.log(mul(2)(4)(2)()); => outputs 16
It is also possible just to return the argument the self invokable function like
console.log( (function(a) { return a; })(1) ); // returns 1
Ok, this may sound a bit crazy but hear me out :)
I would like to do the following in javascript:
define START_OF_EVERY_FUNCTION = "try {"
define END_OF_EVERY_FUNCTION = "} catch () {}"
function TEST () {
START_OF_EVERY_FUNCTION
// rest of function
END_OF_EVERY_FUNCTION
}
Basically, can I define a list of javascript lines (code) and include them as above? I'm looking for a technique versus comments about whether this is a good idea or not or debate over wrapping all functions in a try/catch block.
I know about eval(), but I dont think you can eval statements like the above.
This might be goofy but you could define a master function and run other functions through it by passing them in.
var execute = function(func){
alert('before');
func();
alert('after');
};
function sayHi(){
alert('hi there');
}
execute(sayHi);
As requested, an example with passing arguments.
var execute = function(func){
alert('before');
var ret = func.apply(null, Array.prototype.slice.call(arguments, 1));
alert('after');
};
function saySomething(sayWhat){
alert(sayWhat);
}
execute(saySomething,'hey there');
That is not allowed in JavaScript.
You could extend the Function prototype:
Function.prototype.tryThis = function() {
try {
this();
}catch(ex){
alert('Caught '+ex);
};
};
function tryIt() {
alert('Inside tryIt');throw "My Error from tryIt";
}
tryIt.tryThis();
You need to look into aspect oriented programming for JavaScript. You can create hooks for function entry and exit. Tools like JSUnit do this for example.
I think you can do this with the "new Function" operator. I've never used it myself, since I'm not clinically insane, but I believe you can pass it a string which it will evaluate and use as the function body. You can also get the code for each function by calling myFunction.toString(). So put together, it'd be something like this:
var functionsToMessUp = ['myFunc1', 'myFunc2'];
for (var i = 0; i < functionsToMessUp.length; ++i) {
var theFunc = window[functionsToMessUp[i]]; // assuming they're in global scope
window[functionsToMessUp[i]] = new Function(
START_OF_EVERY_FUNCTION
+ theFunc.toString()
+ END_OF_EVERY_FUNCTION
);
}
Now, the above almost certainly won't work - there's parameters and other things to take into consideration, and I don't even think that's how the new Function constructor works, but if you really want to go down this path (which I really don't recommend), then this might be a good starting point for you.
Maybe something like this?
function tryCatch(callback) {
try {
callback();
} catch() {}
}
var myFunction = function() {
// do some stuff
};
tryCatch(myFunction);