0

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?

Jonius
  • 3
  • 2
  • Strings in Javascript are passed by reference. – Robert Harvey Oct 21 '19 at 20:15
  • 1
    the parameters create local variables, just like `var/let/const` inside a function would. – dandavis Oct 21 '19 at 20:15
  • it does not "mutates" :) , read about variable scopes – oleevier Oct 21 '19 at 20:18
  • 1
    @RobertHarvey that's not true. Primitive values such as strings and numbers are passed by value, it's only objects (which includes arrays and functions) that are passed by reference. – Robin Zigmond Oct 21 '19 at 20:19
  • @RobinZigmond https://stackoverflow.com/a/1308668/102937 – Robert Harvey Oct 21 '19 at 20:20
  • @RobertHarvey it's actually slightly more complicated than I said, technically *all* values are "passed by value" - see [here](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) since we're sharing previous SO questions. But it's definitely not the case that strings are in any sense passed "by reference" in JS, and am surprised to find an accepted answer by a high-reputation user saying that. Nevertheless the statement is wrong, if you google pass-by-reference vs pass-by-value in JS you will see this. – Robin Zigmond Oct 21 '19 at 20:25
  • @RobinZigmond: I've seen other posts on the Internet making the same assertion, but OK, I'll take your word for it. – Robert Harvey Oct 21 '19 at 20:28
  • @RobertHarvey The answer you linked talks about contents of strings in the C++ view on them, which is very confusing. A javascript string is an immutable primitive value, there are no references to it, it's passed by value as anything else. It might be implemented by sharing the character buffer between multiple values, but that's an implementation detail. – Bergi Oct 21 '19 at 22:06

2 Answers2

0

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.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • I think I got it, in Function1 `from` value doesn't change in the global variable because `function showMessage(from, text)` makes a local copy of `from` and `text` and when `from = 'Jane';` the function really is assigning `Jane` value to the local copy `from`. On the other hand, since Funcion2 has no parameters, it obviously does not create any local copies and when I set `userName = 'Bob'` the global variable vale is `Bob` now, If I created a variable `let userName = 'Bob'` then the value of the global variable would not be affected. Right? – Jonius Oct 21 '19 at 21:47
  • Yes, exactly. (Although the `from` parameter in `showMessage` doesn't "make a local copy of `from`", the fact that it shares a name with an outer variable is just coincidence, it takes the value of whatever is passed in when the function is called. It's a local variable, which doesn't affect anything outside the function - that's the key.) – Robin Zigmond Oct 21 '19 at 21:49
  • Yeah, with "make a local copy of from" I meant the first parameter called from. That parameter could have any name and it wouldn't affect it anyway to the global variable. For example, if instead of the parameter `from` I called it `firstName`, the function will create a local variable of name `firstName` and it will have the value `Ann` cause is the value of `from` (variable that I'm passing when I invoke the function). With all this I have clearer this diffence. Thanks a lot! – Jonius Oct 21 '19 at 23:44
0

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 ;)

Thomas Ludewig
  • 696
  • 9
  • 17