Is there something like a best practise when it comes to declaring variables in javascript before assigning a value to them? Sometimes it's necesary for scope reasons, but what if scope doesn't matter?
// Declare first
(function() {
var foo = 'bar',
a = 500,
b = 300,
c;
// Some things get done here with a and b before c can use them...
c = a * b;
// c is now ready to use...
doSomething(c);
}());
// Declare when needed
(function() {
var foo = 'bar',
a = 500,
b = 300;
// Some things get done here with a and b before c can use them...
var c = a * b;
// c is now ready to use...
doSomething(c);
}());
And I'm also wondering what's best practise for something similar with object literals:
// Add property with null assigned to it
var myObj = {
foo: null,
doSomething: function() {
this.foo = 'bar';
}
};
// Property gets added when value is set
var myObj = {
doSomething: function() {
this.foo = 'bar';
}
};
It is mostly a matter of style.
As var declarations are automatically hoisted up to the top of the scope, it makes sense to place them at top of their scope so that you can read the code closer to how the interpreter will execute it.
Declaring variables at the top of their scope is Crockford's recommendation. And it does make sense as it clears up some common misconceptions.
For example:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
Since var has function scope, all iterations (and functions inside of them) refer to the same i. As all three timed functions will execute after the loop ends, the snippet above logs 3 three times.
Now for those with block scoping experience, the above behavior is not very clear. Rewriting the snippet:
var i;
for (i = 0; i < 3; i++) {
// ...
}
Now, i is declared in the global scope, exactly as the previous snippet. However, this one is much more clear on that.
Another misconception:
(function() {
if (true) {
var foo = 1;
} else {
var foo = 1;
}
}());
Again, in block-scoped languages¹ the above is perfectly valid. However, as var declarations are hoisted up to top of the current function scope at parse time, the above is equivalent to:
(function() {
var foo;
var foo;
if (true) {
foo = 1;
} else {
foo = 1;
}
}());
The variable is declared twice. Most browsers will just ignore the second declaration and the code will "work", but static code analysis tools such as JSHint will yell at you.
You can rewrite it with only one declaration and it is perfectly valid:
(function() {
if (true) {
var foo = 1;
} else {
foo = 1;
}
}());
But OCD-like coders like me will find it rather ugly. So again, declaring at top of the scope:
(function() {
var foo;
if (true) {
foo = 1;
} else {
foo = 1;
}
}());
Looks much more tidier.
Again, it is mostly a matter of style. Personally, if I have a giant function, I hate to scroll all the way up just to check whether a variable is already declared and adding it to the list. In that case, I may just add a couple of var declarations in the middle of the function (against Crockford's recommendation) which I personally find easier to read and maintain.
As it is a matter of style, just make sure to keep your code the most maintainable and concise possible.
In the other side of the coin, I'll admit that, personally, I've started and mostly used var declarations when the variable is firstly used. This is an aspect of the language and you can use it this way without problem.
But I will also admit that, if I had followed Crockford's recommendations from the start, I'd have had many less headaches (as with the misconceptions shown above) and would have grasped JavaScript's function scoping aspect much faster.
¹ Note that JS 1.7 introduced block-scoped variables through let, but it is not widely supported yet.
Related
I'm maintaining some legacy code and I've noticed that the following pattern for defining objects is used:
var MyObject = {};
(function (root) {
root.myFunction = function (foo) {
//do something
};
})(MyObject);
Is there any purpose to this? Is it equivalent to just doing the following?
var MyObject = {
myFunction : function (foo) {
//do something
};
};
I'm not about to embark in a holy quest to refactor the whole codebase to my likings, but I'd really like to understand the reason behind that roundabout way of defining objects.
Thanks!
It's called the module pattern http://toddmotto.com/mastering-the-module-pattern/
The main reason is for you to create truly private methods and variables. In your case, it's not meaningful because it's not hiding any implementation details.
Here's an example where it makes sense to use the module pattern.
var MyNameSpace = {};
(function(ns){
// The value variable is hidden from the outside world
var value = 0;
// So is this function
function adder(num) {
return num + 1;
}
ns.getNext = function () {
return value = adder(value);
}
})(MyNameSpace);
var id = MyNameSpace.getNext(); // 1
var otherId = MyNameSpace.getNext(); // 2
var otherId = MyNameSpace.getNext(); // 3
Whereas if you just used a straight object, adder and value would become public
var MyNameSpace = {
value: 0,
adder: function(num) {
return num + 1;
},
getNext: function() {
return this.value = this.adder(this.value);
}
}
And you could break it by doing stuff like
MyNameSpace.getNext(); // 1
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 1 again
delete MyNameSpace.adder;
MyNameSpace.getNext(); // error undefined is not a function
But with the module version
MyNameSpace.getNext(); // 1
// Is not affecting the internal value, it's creating a new property
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 2, yessss
// Is not deleting anything
delete MyNameSpace.adder;
MyNameSpace.getNext(); // no problemo, outputs 3
The purpose is to limit accessibility of functions within the closure to help prevent other scripts from executing code on it. By wrapping it around a closure you are redefining the scope of execution for all code inside the closure and effectively creating a private scope. See this article for more info:
http://lupomontero.com/using-javascript-closures-to-create-private-scopes/
From the article:
One of the best known problems in JavaScript is its dependance on a
global scope, which basically means that any variables you declare
outside of a function live in the same name space: the ominous
window object. Because of the nature of web pages, many scripts from
different sources can (and will) run on the same page sharing a
common global scope and this can be a really really bad thing as it
can lead to name collisions (variables with the same names being
overwritten) and security issues. To minimise the problem we can use
JavaScript’s powerful closures to create private scopes where we can
be sure our variables are invisible to other scripts on the page.
Code:
var MyObject = {};
(function (root) {
function myPrivateFunction() {
return "I can only be called from within the closure";
}
root.myFunction = function (foo) {
//do something
};
myPrivateFunction(); // returns "I can only be called from within the closure"
})(MyObject);
myPrivateFunction(); // throws error - undefined is not a function
advantages:
maintains variables in private scope.
you can extend the functionality of the existing object.
performance is increased.
i think the above three simple points are just enough to follow those rules. And to keep it simple its nothing but writing inner functions.
In the particular case that you show, there is no meaningful difference, in terms of functionality or visibility.
It's likely that the original coder adopted this approach as a sort of template allowing him to define private variables that could be used in the definition of things like myFunction:
var MyObject = {};
(function(root) {
var seconds_per_day = 24 * 60 * 60; // <-- private variable
root.myFunction = function(foo) {
return seconds_per_day;
};
})(MyObject);
This avoids calculating seconds_per_day each time the function is called, while also keeping it from polluting the global scope.
However, there's nothing essentially different from that and just saying
var MyObject = function() {
var seconds_per_day = 24 * 60 * 60;
return {
myFunction: function(foo) {
return seconds_per_day;
}
};
}();
The original coder may have preferred to be able to add functions to the object using the declarative syntax of root.myFunction = function, rather than the object/property syntax of myFunction: function. But that difference is mainly a matter of preference.
However, the structure taken by the original coder has the advantage that properties/methods can be easily added elsewhere in the code:
var MyObject = {};
(function(root) {
var seconds_per_day = 24 * 60 * 60;
root.myFunction = function(foo) {
return seconds_per_day;
};
})(MyObject);
(function(root) {
var another_private_variable = Math.pi;
root.myFunction2 = function(bar) { };
})(MyObject);
Bottom line, there is no need to adopt this approach if you don't need to, but there is also no need to change it, since it works perfectly well and actually has some advantages.
First pattern can be used as a module which takes an object and returns that object with some modifications. In other words, you can define such modules as follows.
var module = function (root) {
root.myFunction = function (foo) {
//do something
};
}
And use it like:
var obj = {};
module(obj);
So an advantage could be the re-usability of this module for later uses.
In the first pattern, you can define a private scope to store your private stuff such as private properties and methods. For example, consider this snippet:
(function (root) {
// A private property
var factor = 3;
root.multiply = function (foo) {
return foo * factor;
};
})(MyObject);
This pattern can be used to add a method or property to all types of objects such as arrays, object literals, functions.
function sum(a, b) {
return a + b;
}
(function (root) {
// A private property
var factor = 3;
root.multiply = function (foo) {
return foo * factor;
};
})(sum);
console.log(sum(1, 2)); // 3
console.log(sum.multiply(4)); // 12
In my opinion the main advantage could be the second one (creating a private scope)
This pattern provides a scope in which you can define helper functions that are not visible in the global scope:
(function (root) {
function doFoo() { ... };
root.myFunction = function (foo) {
//do something
doFoo();
//do something else
};
})(MyObject);
doFoo is local to the anonymous function, it can't be referenced from outside.
Let's say I start up a var for an Object in my code
var base = {x:Infinity, y:Infinity};
and later in the same scope I do
var base = {x:0, y:0}
I get that I can re-use the existing variable, but I'm trying to iterate on a point.
Does this cause any problems for the current scope as far as memory is concerned?
Would there be any problems if these are in different scopes?
Is the general rule to never use var on an already-existing variable?
If I did this several (thousands) of times, would I run into any "funky" issues?
It releases its hold on the old value, so it can be potentially garbage collected. I say potentially, because objects can be referenced by different variables.
If they're in different scopes, the inner base will shadow the outer one (assuming you're talking about nested scopes), so the old value will not be overwritten. Shadowing is usually best avoided.
Generally, within the same scope, yes but that's more of a coding style aspect. It won't make an effective difference in the execution since there's only one declaration no matter how many times you declare the same var in the same scope.
Depends. Are you talking about overwriting in a loop? If you no longer need the current value, it shouldn't be an issue.
To be clear, when you do this:
var base = {x:Infinity, y:Infinity};
var base = {x:0, y:0}
What's really happening is this:
var base; // declaration is hoisted
base = {x:Infinity, y:Infinity}; // new object is referenced by base
base = {x:0, y:0} // previous object is released, and new object is referenced
Note that when I talk about scope and var, I'm talking specifically about function scope. In standard JavaScript/ECMAScript implementations, there is no block scope, so there's no special meaning when using var in a for statement for example.
As mentioned by #Charles Bailey, Mozilla has let, which does allow scoping in blocks, but it would require that specific keyword. The var statement doesn't recognize the block with respect to variable scope.
There is absolutely no problem in doing that. Afterall, variables declared within a function (-context) are just part of the such called Activation Object (ES edition 3). It is a little bit different in ES5, but for this part it is basically the same.
You are just overwritting a property, in an Object (not a Javascript object, but from the underlaying js engine).
So again, that is not a problem at all (even if its unusual und looks confusing).
If you declare a variable in another "scope" (which basically means, another function here), it is also no problem. Each (execution) context is completely on its own and cannot interfer with another context, unless we are talking about closures and stuff. But even then, if you have several functions and parent context which all have the same named variable, the lookup process (name resolution) always begins in your local scope (the Activation object from the current context) and after that, it goes into the "scope chain".
I guess that should answer 3.) and 4.) also. You "can" re-var a variable, but it makes no sense. So I'd just recommend to don't do it anymore.
The var keyword provides scope to a variable. The only scope available to JavaScript at this time is function scope. If the variable is already scoped to this function then setting with the var keyword again does nothing.
JavaScript is lambda language, which means variables declared in a higher scope are available to functions inside that higher scope. Providing a variable from a higher scope with the var keyword in a lower function scope could be harmful, because you have now created a local variable that may be intended as closure. Consider the following two examples:
var a = function () {
var b = 3,
c = function () {
var d = 5;
b = 5;
return d + b; // this is 10
};
return c() + b; // this is 10 + 5, or 15
};
var a = function () {
var b = 3,
c = function () {
var b = 5,
d = 5;
return d + b; // this is 10
};
return c() + b; // this is 10 + 3, or 13
};
I said unintentionally altering variable scope is potentially harmful, because it will confuse how your code works from how you think it should work.
The general rule is one var declaration per function, and that var declaration belongs at the top of the function:
function foo() {
var bar;
}
The reason to do it is to avoid confusion that could be caused by variable hoisting.
An example of where this matters is with closure context for callbacks:
//this looks like it will count up, but it wont
function foo() {
var i;
for (i = 0; i < 10; i++) {
var bar = i;
setTimeout( function () {
console.log(bar);
}, 1000 * i);
}
}
//this is actually what's happening behind the scenes
//hopefully you can see why it wont work
function foo() {
var i, bar;
for (i = 0; i < 10; i++) {
bar = i; //bar is in the same scope as i
setTimeout( function () {
//when this is called `i` and `bar` will both have a value of 9
console.log(bar);
}, 1000 * i);
}
}
If you've got a sub-function, you can declare a new variable of the same name, which will remain for the scope of that sub-function:
function foo() {
var bar;
function baz() {
bar = 2;
}
bar = 1;
baz();
console.log(bar); //output will be 2 because baz operated in the outer scope
}
function foo() {
var bar;
function baz() {
var bar;
bar = 2;
}
bar = 1;
baz();
console.log(bar); //output will stay 1 because baz operated in its own scope
}
If your example code is along the lines of:
function foo() {
var base = {x:Infinity, y:Infinity};
...some code...
var base = {x:0, y:0};
}
It will actually execute as:
function foo() {
var base;
base = {x:Infinity, y:Infinity};
...some code...
base = {x:0, y:0};
}
I'm trying to reuse a complicated function, and it would work perfectly if I could change the value of a local variable that's inside a conditional inside that function.
To boil it down:
var func = complicated_function() {
// lots of code
if (something) {
var localvar = 35;
}
// lots of code
}
I need localvar to be some other number.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Update: The answer is yes! See my response below.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Nope.
No, but it is possible to assign it conditionally so that the function signature (basically, the required input and output) does not change. Add a parameter and have it default to its current value:
var func = complicated_function(myLocalVar) {
// lots of code
if (something) {
// if myLocalVar has not been set, use 35.
// if it has been set, use that value
var localvar = (myLocalVar === undefined)?35:myLocalVar;
}
// lots of code
}
No.
Without changing the complicated function there is no way, in javascript you can manipilate this by using call and apply. You can override functions in the complicated function or add new if this is an option (but they won't be able to access the local variable localvar).
this is more for fun my real answer is still no.
If you are feeling crazy :)
var complicatedFunction = function() {
var i = 10;
var internalStuff = function() {
console.log(i); // 10 or 12?
};
return internalStuff();
};
var complicatedFunction;
eval("complicatedFunction = " + complicatedFunction.toString().replace(/i = 10/, 'i = 12'));
complicatedFunction(); //# => 12
If the function uses this.localvar:
var func = function() {
alert(this.localvar)
if (true) {
var localvar = 35;
}
// lots of code
alert(this.localvar)
}
var obj = {localvar: 10};
func.call(obj); // alerts 10 twice
If not, then you can't change it without changing the function.
In javascript variables are "pushed" to the top of their function. Variables in javascript have function scope, not "curly brace" scope like C, C++, Java, and C#.
This is the same code with you (the developer) manually pushing it to the top:
var func = complicated_function() {
var localvar = 0;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
}
Does declaring the variable "up" one function help you out? At least the declaration is isolated.
function whatever() {
var localvar = 0;
var func = function() {
var something = true;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
};
func();
alert(localvar);
}
whatever();
Here is the jsFiddle: http://jsfiddle.net/Gjjqx/
See Crockford:
http://javascript.crockford.com/code.html
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
I asked this question about three weeks ago and within a half hour got five answers that all basically told me it wasn't possible.
But I'm pleased to announce that the answer is YES, it can be done!
Here's how:
var newfunc = func.toString().replace('35', '42');
eval('newfunc = ' + newfunc);
newfunc();
Of course, it uses eval, which probably means that it's evil, or at least very inadvisable, but in this particular case, it works.
I'm using class members to hold constants. E.g.:
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
This works fine, except that it seems a bit unorganized, with all the code that is specific to Foo laying around in global scope. So I thought about moving the constant declaration to inside the Foo() declaration, but then wouldn't that code execute everytime Foo is constructed?
I'm coming from Java where everything is enclosed in a class body, so I'm thinking JavaScript might have something similar to that or some work around that mimics it.
All you're doing in your code is adding a property named CONSTANT with the value 1 to the Function object named Foo, then overwriting it immediately with the value 2.
I'm not too familiar with other languages, but I don't believe javascript is able to do what you seem to be attempting.
None of the properties you're adding to Foo will ever execute. They're just stored in that namespace.
Maybe you wanted to prototype some property onto Foo?
function Foo() {
}
Foo.prototype.CONSTANT1 = 1;
Foo.prototype.CONSTANT2 = 2;
Not quite what you're after though.
You must make your constants like you said :
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
And you access like that :
Foo.CONSTANT1;
or
anInstanceOfFoo.__proto__.constructor.CONSTANT1;
All other solutions alloc an other part of memory when you create an other object, so it's not a constant. You should not do that :
Foo.prototype.CONSTANT1 = 1;
IF the constants are to be used inside of the object only:
function Foo() {
var CONSTANT1 = 1,CONSTANT2 = 2;
}
If not, do it like this:
function Foo(){
this.CONSTANT1=1;
this.CONSTANT2=2;
}
It's much more readable and easier to work out what the function does.
If you're using jQuery, you can use $.extend function to categorize everything.
var MyClass = $.extend(function() {
$.extend(this, {
parameter: 'param',
func: function() {
console.log(this.parameter);
}
});
// some code to do at construction time
}, {
CONST: 'const'
}
);
var a = new MyClass();
var b = new MyClass();
b.parameter = MyClass.CONST;
a.func(); // console: param
b.func(); // console: const
First, I recommend moving your class declaration inside of an IIFE. This cleans up the code, making it more self-contained, and allows you to use local variables without polluting the global namespace. Your code becomes:
var Foo = (function() {
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
return Foo;
})();
The problem with assigning constants directly to the class as attributes is that those are writable. See this snippet:
var output = document.getElementById("output");
var Foo = (function() {
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
return Foo;
})();
Foo.CONSTANT1 = "I'm not very constant";
output.innerHTML = Foo.CONSTANT1;
<div id="output"></div>
The best solution I have found is to define read-only properties for accessing the constants outside of the class.
var output = document.getElementById("output");
var Foo = (function() {
const CONSTANT1 = "I'm very constant";
function Foo() {
}
Object.defineProperty(Foo, "CONSTANT1", {
get: function() {
return CONSTANT1;
},
});
return Foo;
})();
Foo.CONSTANT1 = "some other value";
output.innerHTML = Foo.CONSTANT1;
<div id="output"></div>
(Technically you could ditch the const CONSTANT1 statement and just return the value from the property definition, but I prefer this because it makes it easier to see all the constants at a glance.)
what you are doing is fine (assuming you realize that your example is just setting the same property twice); it is the equivalent of a static variable in Java (as close as you can get, at least without doing a lot of work). Also, its not entirely global, since its on the constructor function, it is effectively namespaced to your 'class'.
Your constants are just variables, and you won't know if you try and inadvertently overwrite them. Also note that Javascript lacks the notion of "class".
I'd suggest you create functions that return values that you need constant.
To get the taste of Javascript, find Javascript: the Good Parts and learn the idiomatic ways. Javascript is very different from Java.
Also with namespaces
var Constants = {
Const1: function () {
Const1.prototype.CONSTANT1 = 1;
Const1.prototype.CONSTANT2 = 2;
},
Const2: function () {
Const2.prototype.CONSTANT3 = 4;
Const2.prototype.CONSTANT4 = 3;
}
};
You said your coming from Java - why don't you store that class in 1 file then and constants at the end of the file. This is what I use:
filename: PopupWindow.js
function PopupWindow() {
//private class memebers
var popup, lightbox;
//public class memeber or method (it is the same in JS if I am right)
this.myfuncOrmyMemeber = function() {};
}
//static variable
PopupWindow._instance = null;
//same thing again with constant-like name (you can't have "final" in JS if I am right, so it is not immutable constant but its close enough ;) - just remember not to set varibales with BIG_LETTERS :D)
PopupWindow.MY_CONSTANT = 1;
//yea, and same thing with static methods again
PopupWindow._getInstance = function() {};
So only difference is the position of static stuff. It is not nicly aligned inside class curly braces, but who cares, its always ctrl+click in IDE (or I use ctr+l to show all class methods - IntellijIdea can do that in JS dunno how about other IDEs) so your not gonna search it by your eye ;)
Yea and I use _ before static method - it is not needed, I don't know why I started to do that :)
Is there any way to change a variable while out of scope? I know in general, you cannot, but I'm wondering if there are any tricks or overrides. For example, is there any way to make the following work:
function blah(){
var a = 1
}
a = 2;
alert(blah());
EDIT (for clarification):
The hypothetical scenario would be modifying a variable that is used in a setInterval function which is also out of scope and in an un-editable previous javascript file. It's a pretty wacky scenario, but it's the one I intend to ask about.
No. No tricks or overrides. You have to plan to have both places be able to see the variable in the same scope.
The only trick I can think of regarding scope is using window in a browser to get to the global object. This can help you get to a "hidden" variable--one that's in scope but whose name has been overtaken by a local variable (or other variable closer in the scope chain).
Closures and classes can afford you some other tricks with scope, but none that allow you to override the scoping rules entirely.
i don't see why you would need to do that, if you need a variable that is accessible from the outside, just declare it on the outside.
now, if you are asking this just because you are trying to learn something, good for you.
var a = 0;
function blah() {
a = 1;
return a;
}
a = 2;
alert(blah());
You can return the value from the function, of course:
function blah() {
var a=1;
return a;
}
But I assume that's not quite what you had in mind. Because a function invocation creates a closure over local variables, it's not generally possible to modify the values once the closure is created.
Objects are somewhat different, because they're reference values.
function blah1(v) {
setInterval(function() {
console.log("blah1 "+v);
}, 500);
}
function blah2(v) {
setInterval(function() {
console.log("blah2 "+v.a);
}, 500);
}
var a = 1;
var b = {a: 1};
blah1(a);
blah2(b);
setInterval(function() {
a++;
}, 2000);
setInterval(function() {
b.a++;
}, 2000);
If you run this in an environment with a console object, you'll see that the value reported in blah2 changes after 2 seconds, but blah1 just goes on using the same value for v.
Functions can access variables declared outside their scope, if they are declared before the function itself:
var a = 0;
function blah() {
a = 1;
}
a = 2;
alert(blah());
Note that your use of var a inside the function declared a local variable named a; here, we omit the keyword as otherwise it would hide a as declared in the outer scope!
No, that will never work, but you could use a global:
var a;
function blah(){
a = 1
}
a = 2;
alert(blah());
or use a closure:
function bleh() {
var a;
function blah(){
a = 1
}
a = 2;
alert(blah());
}
or you could pass it around with a return (which behaves differently, but probably is what you want to do):
function blah(a){
a = 1
return a;
}
a = 2;
alert(blah(a));