I'm currently studying JavaScript and I have a question with function parameters. I have this function:
//Function 1
let from = 'Ann';
function showMessage(from, text) {
from = 'Jane';
alert(from + ' says ' + text);
}
showMessage(from, 'Hello');
alert(from);
//Function 2
let userName = 'John';
function showMessage1(){
userName = 'Bob'
alert('Hello '+ userName);
}
alert(userName);
showMessage1();
alert(userName);
I can understand that in the Function1 showMessage(from, 'Hello'); displays Jane says Hello and alert(from) displays Ann because when I pass the arguments, the function creates a local copy of the values that I passed. I had read that when you have a same-named global and local variable, local shadows global and I think that it happens in Function1 and that's why I get 'Ann' in the last line.
Then since I don't pass on any argument to the Function2, it doesn't create local copy and that's why the value of userName is equal Bob and it is displayed in the last line.
EDIT: I rephrase my question: Why do they behave differently (one does not overwrite the global variable and the other does) if the only difference that I see is that one is passed parameters and the other is not?
It's because you haven't declared a local variable userName inside showMessage1. Variables are declared with one of the keywords var, let or const (I won't go into the differences here, although they are important). If you did this, then you would get the expected result:
//Function 1
let from = 'Ann';
function showMessage(from, text) {
from = 'Jane';
alert(from + ' says ' + text);
}
showMessage(from, 'Hello');
alert(from);
//Function 2
let userName = 'John';
function showMessage1(){
let userName = 'Bob'
alert('Hello '+ userName);
}
alert(userName);
showMessage1();
alert(userName);
In your snippet, because there is no let (or var or const) before the assignment userName = 'Bob', there is no local variable called userName to assign to, so instead it assigns to the userName variable in the enclosing scope - here the global scope. This is why, in your example, the global userName is overwritten, but it isn't in the version above.
EDIT: I rephrase my question: Why do they behave differently (one does not overwrite the global variable and the other does) if the only difference that I see is that one is passed parameters and the other is not?
To answer this explicitly: the difference isn't to do with being passed parameters or not. The difference is between the assignment inside the function being to a local variable or a non-local (in this case, global) one. In your showMessage, the assignment is to from, which is by definition a local variable because it's a function parameter. In your original showMessage1, the assignment to userName was to the non-local variable from the enclosing (global) scope, since no userName is declared in the function's scope. By declaring the variable with let (or var or const), a local variable of that name is created inside the function, which is then assigned to without affecting the same-named ("shadowed") variable in the enclosing scope.
A very shorthand rule set is that JS do not decides between "byValue" and "byReference". At least not as other Programming languages do that. Everything which is a primitive type is passed by Value ( strings bools and numbers etc). Compund variables e.g. OBJECTS and ARRAYS are passed by reference. And that is it. There is no keyword to tell to act different. If you want to put a Array or Object by Value then create a copy of it. If you want to have a primitive type by reference - create a object of the primitive type. Type less languages like Javascript or REXX and some others handles such things different as languages which relay on a compiler. The compiler HAS to know whats to do exactly. In a scripting language we have a nice interpreter and he can decide in the last second whats right and whats wrong. :) .oO(and sometimes creates some gray hairs by acting like that ;)
Related
This is really tearing apart my JS concept. What's wrong at all here?
const NAME = 'chusss';
var name = 123;
console.log(typeof name); // string, wasnt it supposed to print number?
console.log(name); // 123
The name variable actually belongs to window.name which lets you set the name of the window.
From MDN
The name of the window is used primarily for setting targets for
hyperlinks and forms.
Further down it's written:
Don't set the value to something unstring since its get method will
call the toString method.
Thus you always get a string returned.
If you still want to use the name variable but dont want to have the collision with window.name, then wrap your code inside a immediate invoked function expression (IIFE) and benefit from the functional scope.
Demo
(function() {
var name = 123;
console.log(typeof name);
console.log(name);
})();
If you run this code in node.js you won't observe that behaviour as name is not a property of the global object and thus not defined in global scope.
I have been watching a video series by Douglas Crockford. I am a little confused on the relationship of assigning variables as a parameter of assigning variables as a global variable, let me demonstrate.
var bob = 22; //global scope
function funky(parameter){
parameter = null; //sets the var passed in to null
bob = 44; //sets the bob
}
var hello = [];
funky(hello); // hello still has the value of an empty array even after the function is invoked.
bob; // value is 44
So 'var bob' is assigned 44 when funky() is invoked. This bob holds the new value outside the scope of the function.
var hello is passed as a parameter, while inside funky, it has the value null, outside when hello is invoked in global space, it holds the value of an empty array.
Is this just something I have to memorize? If a defined variable in global scope is passed as a parameter, it will only hold it's new assigned value within the scope of the function? Am I missing something at a broader scope with either how a parameter is passed and assigned in a function?
Here is a repl.it of the code with console.log outputs while inside and outside the function/global scope.
http://repl.it/NgN
Because this line
parameter = null;
Only sets the value of the function's parameter, not the value of the variable that was passed in. However, bob inside the function is interpretted as a reference to the global variable, so it does modify the external value.
Note, however, that objects are references, so if you wrote it like this:
function funky(parameter){
parameter.hello = null;
}
Then calling funky does directly modify the object that the parameter references.
var x = { hello: [] };
funky(x); // x => { hello: null }
Is this just something I have to memorize?
Yes, understanding how parameters are passed is pretty important.
If a defined variable in global scope is passed as a parameter, it will only hold it's new assigned value within the scope of the function?
Parameters only hold their values within the scope of the function. Global variables are, well, global, so if they are modified inside the function, they keep that value outside the function.
Also, be aware of hiding—if a parameter has the same name as a global variable, the parameter hides the variable within the scope of that function.
ok, so the following example will confuse you even more.
var a = {'a': 'A'};
function foo(param){param.a = 'B';}
foo(a);
// now print a
{'a': 'B'}
Here's an important concept:
Primitives are passed by value, Objects are passed by "copy of a reference".
As for more information, you can check this answer:
Does Javascript pass by reference?
Regarding this:
var hello is passed as a parameter, while inside funky, it has the value null, outside when hello is invoked in global space, it holds the value of an empty array.
Do not think of parameter as an alias for hello. They are distinct variables. They are free to point to different things. Assigning a value -- null in this case -- to parameter has no effect on hello. After that line, the global variable hello still points to an empty array. Only parameter points to null.
Furthermore, funky(hello) passes the value of hello to the funky function. Consider the following:
var arr = [];
function addElements(arr) {
arr.push(5);
arr.push(77);
}
The global arr is still empty after addElements executes. The arr inside the function is distinct from the arr in the global scope. (I should note that the contents of each arr may point to the same objects, but that's a separate issue.)
(Note also that some languages do allow the sort of aliasing you seem to expect, but that's not how parameters are passed in JavaScript.)
JavaScript assumes that if you assign a value to a variable it is in the global scope—unless that variable is declared with a var. Like for example, this:
var bob = 22; //global scope
function funky(parameter){
parameter = null; //sets the var passed in to null
var bob = 44; //sets the bob
}
var hello = [];
funky(hello); // hello still has the value of an empty array even after the function is invoked.
bob; // value is 22
Since the function's bob variable is declared with a var, it is owned by the local scope of the function and has no impact on the bob declared outside the function's scope.
Regarding how objects differ from primitives when passed into functions, check out Jonathan Snook's article http://snook.ca/archives/javascript/javascript_pass and the helpful comment from #p.s.w.g.
Apologies for what must seem like a very stupid question.
I'm currently working through codecadamy, and this is throwing me off:
var greeting = function(name) {
name = "sausage";
console.log(name);
};
greeting(name);
I understand that I will get sausage
Why don't I just write var name = "sausage";? What is the difference?
The name in function(name) is a parameter. That is, it is used to pass data into the function. But, parameters are local variables. Assigning a value to name inside the function is a little strange though. I would assume you want to do something like this:
var greeting = function(name) {
console.log(name);
};
greeting("sausage");
In this version of the code you are passing the value "sausage" into the function via the parameter name. This is useful because you can call the function many times and each time the function may print a different value depending on what you pass.
In your function definition:
function(name) {
name is already being declared. It is a parameter for the function. If you want to change name, you can, but you don't need to use var to declare it as a new variable.
On the other hand, if you wanted to add, say, flavor, you should use var then since it is not already defined.
var flavor = 'savory';
In this case, flavor is a local variable and name is a parameter. A parameter is a type of local variable that is declared with the function declaration, but a local variable isn't necessarily a parameter because it may be declared elsewhere in the function.
Parameters are a general programming construct and are necessary to do anything sane in the world programming (dealing with masses of global variables is not sane.
var name would declare a new variable in the function scope that would override the value of the parameter name, so you would not be able to use the parameter anymore.
The CodeAcadamy example is a bit strange because it's rare that you want to override a parameter's value -- especially before you have used it.
Technically, there is no real difference.
Without giving you the huge background here, you have to understand that in the underlaying implementation, a special object (not a javascript object, on C/C++ level) is formed which is called Activation Object (ES3) or Lexical Environment Record (ES5).
However, this hash / object structure is used to store
variables declared by var
formal parameters
function declarations
As you can see, both var variables and parameters are stored in this structure.
This construct is most likely used to have somewhat default values for not passed in arguments. In a real world example, this would probably look more like
var greeting = function( name ) {
name = name || 'default';
console.log( name );
};
greeting('john'); // 'john'
greeting(); // 'default'
I was wondering how does javascript(if possible) access a variable that has the same name as the variable input of the function.
function myfunc(var1)
{
var var1 = "World";
alert(var1);
}
How can I tell the function which var1 to print?
That doesn't actually define a second variable with the same name. Even with the var statement you are just overwriting the function parameter of the same name.
Just give your second variable a unique name.
(By the way, even if this actually worked it would still be a bad idea because it would make your code hard to read.)
nnnnnn is correct, I tested it. Arguments that are passed to a function can be accessed in 2 ways, by their parameter name and through the arguments variable. arguments[0] would be the value of the first parameter.
In the example below you would expect 2 alerts, the first one saying "Hello" and the second saying "World". But they both say "World" proving that assigning var1 actually changes the value of the argument being passed to the function.
function myfunc(var1) {
var var1 = "World";
alert(arguments[0]);
alert(var1);
}
myfunc("Hello");
var str = 'internet';
performAction(function(str) {
console.log(str);
});
Is there a problem with having a private variable str and also having a callback function with a parameter of the same name?
Thanks!
This is just a standard scope situation - the fact that it is an anonymous function expression passed as a parameter to another function doesn't matter. Note that within your performAction() function (which you don't show) it will not have any access to the str that is the parameter of the callback function - if performAction() references str it will get the global "internet" variable (or its own local str if defined).
A function's parameters are, for scope purposes, the same as that function's local variables, which means they mask other variables of the same name from outer scope - but variables with different names can still be accessed even if defined in a wider scope.
Where it could get confusing is if you do something like this:
var str = "internet";
(function(str) {
console.log(str); // "internet"
str = "local param";
console.log(str); // "local param"
})(str);
console.log(str); // "internet"
In that case I have a function with a parameter called str but when I call it I'm passing in a different str. Note that changing str within that function only changes the local str, not the global one. They are two different variables...
There is technically no problem with it. The function will log the str that is currently in scope (your parameter).
For obvious reasons, this is not considered a good idea. At the very least, it makes for unreadable code.