Is it valid to use variable names again and again? For example:
function clicks() {
var foo = document.getElementById("cat");
foo.click();
var foo = document.getElementById("dog");
foo.click(); // Again! This works, but may be it is not valid?
}
Or I should use unique variable names, like below?
function clicks() {
var foo1 = document.getElementById("cat");
foo1.click();
var foo2 = document.getElementById("dog");
foo2.click();
}
Yes, it is valid. This is because the interpreter "hoists" the variable declaration. That is, it moves the declaration to the top of the current function scope.
To the interpreter, your code "looks" like this:
function clicks () {
var foo;
foo = /* something */
foo = /* something */
}
Now, if you don't want this behavior, you can use let, which stays at the current scope. For example:
function bar () {
if (true) {
let foo = 5
}
console.log(foo) // not defined
// you would need to declare foo again with `let foo = ...`
}
There's nothing wrong with overwriting the value of a variable. Do note that it can make the behavior of your application more confusing, e.g., if someone reading through your code misses where you redeclare the variable. Note that after you've declared it once you can just do foo = document.getElementById("dog"); instead of var foo = document.getElementById("dog");.
Technically, yes, you can use multiple variables with the same name but they all of them will share the same entity. It will be just one variable under that name.
But practically you should avoid that.
You can't re instantiate a variable in js so the var foo twice should not even work:/
the solution is to use something like this
function clicks() {
var foo = document.getElementById("cat");
foo.click();
//remove var in this line...
foo = document.getElementById("dog");
foo.click(); // Again! This works, but may be it is not valid?
}
Related
I'm trying to learn some OOP, so bear with me. I need to use a variable I defined in one function, elsewhere. Here is my example code (I want INTERCEPT!! to be logged, but it returns undefined):
function Talk() {
var greeting;
var pleaseStop; // declare it
this.A = function () {
greeting = 'hello';
console.log(greeting);
var intercept = function () {
pleaseStop = 'INTERCEPT!';
}
}
this.B = function () {
greeting = 'goodbye';
console.log(pleaseStop); // this returns undefined!
console.log(greeting);
}
}
var activateTalk = new Talk();
activateTalk.A();
activateTalk.B();
This whole code logs the following:
hello
undefined
goodbye
I have also tried intercept.pleaseStop() but it still returns undefined. Would anyone know of a solution?
EDIT:
I've removed the var the second time, but it still returns undefined:
http://jsfiddle.net/d654H/2/
var pleaseStop = 'INTERCEPT!';
You're declaring a new, function-local variable here; drop the var to assign to the existing variable in scope.
Then, you need to actually call intercept; at the moment you only define it.
It's your choice as to when you call that function; in this live example I simply do so immediately after the definition, for the purposes of exposition.
Remove var in front of the assignment to pleaseStop.
This assigns a new value to the pleaseStop declared inside the constructor, which is visible also from inside B:
var intercept = function () {
pleaseStop = 'INTERCEPT!';
}
This declares a new local variable pleaseStop, completely unrelated to the other pleaseStop, that is not visible outside intercept:
var intercept = function () {
var pleaseStop = 'INTERCEPT!';
}
If you do the latter instead of the former, you end up changing the value of another variable than the one you intended.
Your problem is you never set pleaseStop. You have declared intercept as a function, but you never called it. Therefore, pleaseStop is undefined.
Firstly you have't called intercept() anywhere and also u did something
var pleaseStop = 'INTERCEPT!';
which will create new variable instead of initializing global variable
You can do something like this
function Talk() {
var greeting;
var pleaseStop; // declare it
this.A = function () {
greeting = 'hello';
console.log(greeting);
var intercept = function () {
pleaseStop = 'INTERCEPT!';//changed
}
intercept(); //..Added
}
this.B = function () {
greeting = 'goodbye';
console.log(pleaseStop); // this returns undefined!
console.log(greeting);
}
}
var activateTalk = new Talk();
activateTalk.A();
activateTalk.B();
Without var keyword.
var pleaseStop = "A";
function foo(){
pleaseStop = "B"; // overwriting to "B"
}
foo();
alert(pleaseStop); // shows "B"
With var keyword.
var pleaseStop = "A";
function foo(){
var pleaseStop = "B"
// This defines a new variable 'pleaseStop'
// in the scope of function foo(){}.
}
foo();
alert(pleaseStop); // shows "A"
Variable Scope
JavaScript has function-level scope. In most languages which have block-level variable scope, variable are accessible whithin their block surrounded by curly brackets ({and}). But JavaSciprt doesn't terminate scopes at the end of blocks, but terminate them at the end of functions.
I'm sure there are many articles and documents about it. I googled it and found an intresting introductory article.
http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/
Hope this helps.
One of my friends was taking an online quiz and he asked me this question which I could not answer.
var global = false;
function test() {
global = true;
return false;
function global() {}
}
console.log(global); // says false (As expected)
test();
console.log(global); // says false (Unexpected: should be true)
If we assume that functions are hoisted at the top along with var variables, let's try this one.
var foo = 1;
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
Here is a JSBin Demo and JSBIN Demo2 to play with.
PS: If we remove function global() {} from test(), then it runs fine. Can somebody help me understand why is this happening ?
var statements and function declaration statements are "hoisted" to the top of their enclosing scope.
Therefore, the function global(){} in your function creates a local global name.
Assigning to global inside your functions binds to this local name. Here's how you can "rewrite" it using hoisting to understand how the compiler sees it:
function test() {
var global = function() {}; // hoisted; 'global' now local
global = true;
return false;
}
I'll answer the second part of your question,
If we assume that functions are hoisted at the top along with var variables
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
You should try console.log(bar()); console.log(foo); instead. However, what hoisting does to your function is this:
function bar() {
var foo;
function foo() {}
return foo;
foo = 10;
foo = 11;
}
So you should expect to get the function returned, since your variable assignments are after the return statement. And both the var and the function declaration make foo a local variable, so the global foo = 1 is never changed.
How does JavaScript deal with functions with names ending with ()? Consider for example the following piece of code:
var foo() = function () { }; // The empty function
var bar = function(foo) { var myVariable = foo(); };
It seems like there are two possible interpretations for what foo(); means:
Execute the argument foo. This assigns myVariable the returned value of foo.
Consider foo() as the name of the function defined at first. This assigns myVariable the empty function.
Is this even legal code? If so, what are the rules?
Is this even legal code?
No:
var foo() = function () { };
should be:
var foo = function () { };
If so, what are the rules?
In this case the foo argument will have precedence because it is defined in an inner scope than the foo function. So it's really a matter of scope: where is the variable defined. The interpreter first starts by looking in the innermost scope of the code, then in the outer, ... until it reaches the global scope (the window object).
So for example the result of the following code will be 123 as seen in this live demo:
var foo = function () { alert('we are in the foo function'); };
var bar = function(foo) { var myVariable = foo(); alert(myVariable); };
bar(function() { return 123; });
The () isn't considered part of the name. You'll probably get a syntax error. You can find some naming rules here.
In javascript, brackets mean execute. So your code will fail as it will be looking for a function foo on the first line.
Identifiers may not contain any parentheses, so the first statement is illegal. The second, however, is fine, myVariable = foo() executes the foo parameter and assigns the return value.
Do you really mean "Can I pass functions as references?" If so, then the answer is yes:
var foo = function() { return 2; }
var bar = function(fn){ return fn(); }
var two = bar(foo);
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 :)
Consider this javascript code:
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
When running this code I get "A". Is this behavior a part of javascript specification and can I rely on it?
In other examples, nothing was passed by value; everything was passed by reference.
bar and foo are BOTH pointers
All vars/handles to NON primitive objects in javascript are pointers; pointers ARE native to javascript, they are the default.
var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar; //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); }; //bar points to function2
foo(); //foo is still a pointer to function1
You will run into hidden errors and bugs if you think they are copies. Especially so if you work with complex objects. For example
function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john
To really COPY a non-primitive in javascript takes more work than just a = b.
For example:
function person(name){ this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__ //useful in some cases
john.name = "jack"
backup.name //john
Yes that is expected and by design.
Your question is basically: does foo reference bar as a pointer or reference would in another language?
The answer is no: the value of bar at the time of assignment is assigned to foo.
I'm a bit late here but I thought I'd give an answer anyways and flesh something out.
It's best not to think in terms of pointers and memory references when discussing the internals of JavaScript (or ECMAScript) when dealing with the specifications. Variables are environment records internally and are stored and referenced by name, not memory address. What your assignment statement is doing, internally and by design, is looking up the environment record name (either "foo" or "bar") and assigning the value to that record.
So,
var bar = function () { alert("A"); }
is assigning the environment record "bar" the value (anonymous function).
var foo = bar;
internally calls GetValue("bar") which retrieves the value associated with the record "bar" and then associates that value with the record "foo". Hence, afterwards the original value of bar can still be used as it's now associated with foo.
Because JavaScript references by string and not memory address is precisely why you can do things like this:
someObject["someProperty"]
which is looking up the value based on the property name.
You are assigning the value of an anonymous function to a variable not a pointer.
If you want to play with pointers, you can use objects that are passed by reference, not copy.
Here are some examples:
"obj2" is a reference of "obj1", you change "obj2", and "obj1" is changed. It will alert false:
var obj1 = {prop:true},
obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);
"prop" points to a property that is not an object, "prop" is not a pointer to this object but a copy. If you change "prop", "obj1" is not changed. It will alert true:
var obj1 = {prop:true},
prop = obj1.prop;
prop = false;
alert(obj1.prop);
"obj2" is a reference to the "subObj" property of "obj1". if "obj2" is changed, "obj1" is changed. It will alert false:
var obj1 = {subObj:{prop:true}},
obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
Yes, there's nothing special about the fact that the variables are referring to functions, there's no aliasing involved.
var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
Yes, this is the correct behavior.
//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
This is assigning a variable to an unnamed function, not a pointer to a function
Yes, you've created a pointer to the original "A" function. When you reassign bar, you're reassigning it, but you're still leaving any references to the old function alone.
So to answer your question, yes, you can rely on it.
Those are not function pointers (and there are no pointers in JS natively). Functions in JS can be anonymous and are first class objects. Hence
function () { alert("A"); }
creates an anonymous function that alerts "A" on execution;
var bar = function () { alert("A"); };
assign that function to bar;
var foo = bar;
assign foo to bar, which is the function "A".
bar = function () { alert("B"); };
rebind bar to an anonymous function "B". This won't affect foo or the other function "A".
foo();
Call the function stored in foo, which is the function "A".
Actually in languages where there are function points e.g. C it won't affect foo either. I don't know where you get the idea of getting "B" on reassignment.
void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
I would just like to add this also works for pre-defined named functions as well:
function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();
This will do the same thing, indicating that function names act like array names (pointers).
For each FunctionDeclaration f in code, in source text order do:
Let fn be the Identifier in FunctionDeclaration f.
Let fo be the result of instantiating FunctionDeclaration f as described in Clause 13.
Let funcAlreadyDeclared be the result of calling env’s HasBinding concrete method passing fn as the argument.
If funcAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing fn and configurableBindings as the arguments.
References
ECMAScript-5: Section 10.5