Should var be used when variable is already a parameter (Javascript) - javascript

I have a function like so
function foo(x){
if (typeof x === 'undefined'){
var x = 123;
}
}
is the var statement necessary? JSlint complains that variable x hides argument (probably b/c I am defining a variable in the scope of the if statement.

The var is not necessary, and in fact it is a mistake. You should use var to declare a new variable. Once the function has an argument x it is declared - whether it is passed a value or not.
By the way, in such cases when you know the variable is declared but just don't know whether it's been assigned a value or not, you can write x === undefined - using typeof and a string comparison is not necessary.

No var is not needed here and it's in fact very misleading. The var modifier is used to scope a value to the current function scope. Hence it's most useful at the top of the method or at worst on the first usage of the value. Parameters are always scoped to the current function hence it has no value.
Using it for subsequent usages suggests it's the first use / declaration of the value. This can be misleading to future developers.

Related

If a var in JavaScript is defined twice, which definition should the interpreter take? [duplicate]

This question already has answers here:
Using the variable "name" doesn't work with a JS object
(4 answers)
Closed 3 years ago.
I'm new to JavaScript and am trying to understand the concepts of hoisting and scope.
Case 1
var name;
function logName(num) {
console.log(name, num);
}
logName(1);
name = "Auro";
logName(2);
and I have the following output in the console
Auro 1
Auro 2
If I understand hoisting correctly, JS engine hoists the declaration of a variable first and then automatically assigns a value undefined to it. Only when it encounters the assignment (=) operator, does it actually assign the intended value to it.
If my understanding above is correct, then the first time the logName function was called, the variable name should have printed undefined, but it is printing the value.
Case 2
var name;
function logName(num) {
console.log(name, num);
}
logName(1);
name = "Auro";
logName(2);
name = "Baner";
Output in the console:
Baner 1
Auro 2
This confuses me even more. Here the first call to the function logName picked the later assignment to the variable and printed Baner, however, the second call picked the previous assignment, that is Auro.
What is going on here? What am I missing?
In the global scope, name refers to window.name, that is the name property of the window - which in the examples you gave are sif1 and sif2 (possibly "Snippet IFrame 1/2").
Since window.name already exists, var name; in the global scope does nothing. The variable is already defined.
Until you overwrite it - and note that again you are setting the global window.name property. And, depending on browser settings, this can persist across reloads of the page (since you're naming the entire window). This explains why you see the value "stick".
No none of the specified output matches, as initially you have value of name equal to window.name, so initially the value of name variable will be equal to winow.name and once overwrite it you get the new value
let's understand how this all works
You can understand as such there are two phase of code execution
Creation phase
Execution phase
Creation phase:- During creation phase function is hoisted at top as it is, while the variable are hoisted but there is no value assigned to it ( or you can say it's value is undefined )
Execution phase:- During execution context it assigns value to variable when it reaches line where assignment is happening
var name;
function logName(num) {
console.log(name, num);
}
logName(1);
name = "Auro";
logName(2);
name = "Baner";
As addition to other answers I can say, that just not use var but use ES6 let or const instead and 'surprising behaviour' will disappear.
let name;
function logName(num) {
console.log(name, num);
}
logName(1);
name = "Auro";
logName(2);
name = "Baner";

The local var does not override the parameter of the same name?

This just blew my mind:
function f(x) {
var x;
console.log(x); // prints 100!
}
f(100);
I always used to think that whenever you declare the local variable, anything with the same name that was declared before becomes hidden behind it. Why var x does not make x undefined as it used to do in other situations?
Compare with this code, which behaves as I used to:
var x = 100;
function f() {
var x;
console.log(x); // prints undefined as expected
}
f();
Both var and the parameter declare the same variable x in the same function scope. When the variable is created, it is initialised to undefined, and shortly after assigned the value 100 that was passed as the argument.
For function code, parameters are also added as bindings to that Environment Record.
The defined parameter x is scooped to the current function. Since x is already been declared in the function, as a parameter, the var x; declaration will be ignored.
For more details: http://es5.github.io/#x10.5
From MDN#var:
Description
...If you re-declare a JavaScript variable, it will not lose its value.
In the first example, since x is already declared within the function f (as an argument), redeclaring it (using var) inside the same function will keep the same value for x before that redeclaration (which is the parameter given to f when it is called).
In the second example, x is declared within the function f. So when looking up x's value to pass on to log we use that x inside f (not the outside one), and since we didn't explicitly give it a value (initializing it), its value is going to be undefined.

Access variable in if block

var func = function () {
var i: number = 0;
if (i == 0) {
var y: number = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
func(); // output: 1
As you can see, I've declared variable y inside if block. So, I think it couldn't be referenced outside the scope.
But, when I've tried to run the code, the output is 1.
Is it an issue in typescript/javascript?
Variables in Javascript are hoisted, meaning that var y is moved to the top of the function as if it were declared there.
Initialization, however is not hoisted, so if you change i to be something other than 0, the variable y will still exist, but it will have the value undefined.
This means that the function is exactly equivalent to:
var func = function () {
var i: number = 0;
var y: number;
if (i == 0) {
y = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
To get the behavior you expect, you need to use let, which is a part of ECMAScript 2015 (ES6). It is block scoped, as you expect. It will also effectively work so that it is accessible only from the point of definition onwards, which is also probably as you would expect.
If you re-declare a JavaScript variable, it will not lose its value.
The second reference might pave way for a new variable syntax. Actually if you recall variable declaration is not neccessary in javascript. Simpe
y=1;
also works.
The second time when you reference y, outside if block, in my opinion, it tries a re-declaration and retains the old value.
Reference - http://www.w3schools.com/js/js_variables.asp
& http://www.w3schools.com/js/js_scope.asp
Javascript has function scope afaik. Any variable declared within a function, should be accessible from anywhere within the function. So, if you have a function checking if i==0, then you can achieve what you are trying to achieve.
This is as it is supposed to be. Javascript scopes by function, not by block. (This does make it unlike many popular languages)
Variables declared like var myVar = 10; will seep into nested functions but not the other way around. Variables declared like myVar = 10; will go global.
I couldn't find anything which suggested that typescript was any different.
Variables declared inside of an if statement are not scoped to the if statement. They're scoped to the current execution context. There's the Global execution context and then when a function is run, it creates it's own execution context. Inside of your function, you created the variables y and i. It doesn't matter that y was created inside of the if statement, because once it runs, y is created in the scope of the function. So then you do y.toString(), which can access y because it's scoped to the function not the if statement. That's why you get the output of 1. This is not an error, it's by design.

function(a){ var a='test'; } : Is "var" required? What if a is undefined?

Quite a javascript 101 question, but, here goes:
function test(a){
var a='test';
}
Is the "var" required to keep the variable from going global?
function test(a){
a='test';
}
Would this suffice?
How about if the function is called with a undefined?
function test(a){
a='test';
}
test();
In the above snippet, would a become global?
Every parameter is implicitly a var.
(The argument value supplied doesn't matter.)
You can pass arguments to a function. These are considered local variables inside the functions scope regardless of wether the function is called with those arguments or not.
If the function is called without supplying a value for all the arguments, the arguments that are not passed when calling the function are set to a value of undefined, but they are still declared inside the functions scope as locals.
function test(a){
var a = 'test';
}
Is the "var" required to keep the variable from going global?
No the var keyword is not required, and in fact should not be used, as you're redeclaring the a variable, and redeclaring variables is not allowed.
function test(a){
a = 'test';
}
Would this suffice?
Yes, that's fine and is the way it should be done. You alread have a variable named a, and now you're setting it to a different value.
How about if the function is called with a undefined?
function test(a){
a = 'test';
}
test();
As mentioned above, it doesn't matter, the argument a is still declared as a local variable inside the function, the value is just set to undefined, so the var keyword should not be used as you're not creating a new variable, a already exists, you're just giving it a new value.
If you are not using "use strict" then if you don't use var, a will be attached to the global namespace implicitly, which in a browser is equivalent to window.a. This is known as "polluting the global namespace" and is generally considered bad practice.
This is not the same as a formal argument bound to a name, as is in your examples. This lives in the function scope as 'a'
However, if you use "use strict", the absence of var throws an error in environments that support "use strict" for any variables not formally bound in the function signature. It basically safeguards against bad practices and potential mistakes/bugs in your code that are easy to make
Edit:
I actually think its worth mentioning let too, which is a way of explicitly binding a variable for use in a given scope. So you needn't use var, if you use let
Check support for this keyword in your environment first!
Well, there are some points to comment:
First of all, within a function variables must have var if they are not a reference to an outside var:
var outside_var = "OUT!";
var myFunction = function() {
var inner_var = "IN";
console.log(outside_var); //Will prompt "OUT!"
console.log(inner_var); //Will prompt "IN"
}
console.log(outside_var); //Will prompt "OUT!"
console.log(inner_var); //Will prompt undefined
Another point is that every var defined as an argument, is already defined in function scope, you don't need to declare it with var:
var outside_var = "OUT!";
var myFunction = function(a) { //imagine you call myFunction("I'M");
var inner_var = a + " IN";
console.log(outside_var); //Will prompt "OUT!"
console.log(a); //Will prompt "I'M"
console.log(inner_var); //Will prompt "I'M IN"
}
console.log(outside_var); //Will prompt "OUT!"
console.log(a); //Will prompt undefined
console.log(inner_var); //Will prompt undefined

Clarification of JavaScript variable scope

I already know how to make this code work, but my question is more about why does it work like this, as well as am I doing stuff right.
The simplest example I can make to showcase my issue is this :
Lets say I have a function that increments the value of an input field by 10 on the press of a button.
var scopeTest = {
parseValue : function( element, value ) {
value = parseInt( element.val(), 10 );
//Why does this not return the value?
return value;
},
incrementValue : function( element, button, value ) {
button.on('mousedown', function (e) {
//Execute the parseValue function and get the value
scopeTest.parseValue( element, value );
//Use the parsed value
element.val( value + 10 );
e.preventDefault();
});
},
init : function () {
var element = $('#test-input'),
button = $('#test-button'),
value = '';
this.incrementValue( element, button, value );
}
};
scopeTest.init();
The above code doesnt work because the parseValue method doesn't properly return the value var when executed inside the incrementValue method.
To solve it apparently I have to set the scopeTest.parseValue( element, value ); parameter to the value variable like this:
value = scopeTest.parseValue( element, value );
Than the code works.
But my question is why? Why is this extra variable assignment step necessary, why the return statement is not enough? Also I am doing everything right with my functions/methods, or is this just the way JavaScript works?
Working example here => http://jsfiddle.net/Husar/zfh9Q/11/
Because the value parameter to parseValue is just a reference. Yes, you can change the object, because you have a reference, but if you assign to the reference it now points at a different object.
The original version is unchanged. Yes, the return was "enough", but you saved the new object in a variable with a lifetime that ended at the next line of code.
People say that JavaScript passes objects by reference, but taking this too literally can be confusing. All object handles in JavaScript are references. This reference is not itself passed by reference, that is, you don't get a double-indirect pointer. So, you can change the object itself through a formal parameter but you cannot change the call site's reference itself.
This is mostly a scope issue. The pass-by-* issue is strange to discuss because the sender variable and the called functions variable have the same name. I'll try anyway.
A variable has a scope in which it is visible. You can see it as a place to store something in. This scope is defined by the location of your function. Meaning where it is in your source code (in the global scope or inside a function scope). It is defined when you write the source code not how you call functions afterwards.
Scopes can nest. In your example there are four scopes. The global scope and each function has a scope. The scopes of your functions all have the global scope as a parent scope. Parent scope means that whenever you try to access a name/variable it is searched first in the function scope and if it isn't found the search proceeds to the parent scope until the name/variable is found or the global scope has been reached (in that case you get an error that it can't be found).
It is allowed to define the same name multiple times. I think that is the source of your confusion. The name "value" for your eyes is always the same but it exists three times in your script. Each function has defined it: parseValue and incrementValue as parameter and init as local var. This effect is called shadowing. It means that all variables with name 'value' are always there but if you lookup the name one is found earlier thus making the other invisible/shadowed.
In this case "value" is treated similar in all three functions because the scope of a local var and a parameter is the same. It means that as soon as you enter one of the methods you enter the function scope. By entering the scope the name "value" is added to the scope chain and will be found first while executing the function. And the opposite is true. If the function scope is left the "value" is removed from the scope chain and gets invisible and discarded.
It is very confusing here because you call a function that takes a parameter "value" with something that has the name "value" and still they mean different things. Being different there is a need to pass the value from one "value" to the other. What happens is that the value of the outer "value" is copied to the inner "value". That what is meant with pass-by-value. The value being copied can be a reference to an object which is what most people make believe it is pass-by-reference. I'm sorry if that sounds confusing but there is too much value naming in here.
The value is copied from the outer function to the called function and lives therefor only inside the called function. If the function ends every change you did to it will be discarded. The only possibility is the return your "side effect". It means your work will be copied back to a variable shortly before the function gets discarded
To other alternative is indeed leaving of parameters and work with the scope chain, e.g. the global scope. But I strongly advize you not to do that. It seems to be easy to use but it produces a lot of subtle errors which will make your life much harder. The best thing to do is to make sure variables have the most narrow scope (where they are used) and pass the values per function parameters and return values.
This isn't a scoping issue, it's a confusion between pass-by-reference and pass-by-value.
In JavaScript, all numbers are passed by value, meaning this:
var value = 10;
scopeTest.parseValue( element, value );
// value still == 10
Objects, and arrays are passed by reference, meaning:
function foo( obj ){
obj.val = 20;
}
var value = { val: 10 }
foo( value );
// value.val == 20;
As others have said it's a pass-by-ref vs pass-by-val.
Given: function foo (){return 3+10;} foo();
What happens? The operation is performed, but you're not setting that value anywhere.
Whereas: result = foo();
The operation performs but you've stored that value for future use.
It is slightly a matter of scope
var param = 0;
function foo( param ) {
param = 1;
}
foo(param);
console.log(param); // still retains value of 0
Why?
There is a param that is global, but inside the function the name of the argument is called param, so the function isn't going to use the global. Instead param only applies the local instance (this.param). Which, is completely different if you did this:
var param = 0;
function foo() { // notice no variable
param = 1; // references global
}
foo(param);
console.log(param); // new value of 1
Here there is no local variable called param, so it uses the global.
You may have a look at it.
http://snook.ca/archives/javascript/javascript_pass

Categories

Resources