1
<!DOCTYPE HTML>
<html>
<body>

<script>
sayHi(1,2,3)

function sayHi(x,y,z) {
    alert("1:"+arguments[0]);// alert 1 as expected
    alert("2:"+arguments[1]);// alert 2 as expected
    alert("3:"+arguments[2]);// arert 3 as expected
    [].shift.call(arguments); 
    [].shift.call(arguments); 
    [].shift.call(arguments); 

    alert("4:"+x);           // alear 3, why?? :/  
    alert("5:"+y);           // alert 3, why?? :/  
    alert("6:"+z);           // alert 3, why?? :/  
    alert("7:"+arguments[0]);           // undefined, no x any more :/  
    alert("8:"+arguments[1]);           // undefined, no y any more :/  
    alert("9:"+arguments[2]);           // undefined, no z any more :/  
 }

</script>
</body>
</html>

I understand that there is a special pseudo-array inside each function called arguments. The code above shift the first element of the arguments, but when I try to alert the value of parameters x,y,z, all the values are 3 instead of undefined. If there is link between arguments and parameters, then arguments[0] -> x, arguments[1]->y, arugments[2]->z, how can arguments[0],arguments[1],arguments[2] all become undefined while parameters x,y,z all be 3??

2
  • 2
    Interesting fact: the actually named arguments get associated with their position in the arguments array unless they are not becoming undefined. So if you shift to the left, you overwrite the values only if they don't become undefined. You can check this out by only shifting once, then you see that x becomes 2 and y becomes 3 and z stays 3. Funny thing this javascript ;)
    – Markai
    Commented Nov 3, 2014 at 11:47
  • @Markai thanks, I read your comment again, I find you answered my question! thanks again! Commented Nov 5, 2014 at 11:06

2 Answers 2

1

what is the link between arguments and parameters in Javascript? I understand that there is a special pseudo-array inside each function called arguments.

Yes. And in sloppy mode, assignment to it is special - every property (0, 1, 2) is a getter/setter reference to the named parameter of that ordinal.

Which means when you assign to x, arguments[0] will have that value as well. And when you assign to arguments[0], the x variable will get that value as well.

So, to explain your snippet we will need to determine what the shift.call does. The spec tells us: it moves all values one to the beginning, deletes the last index, and decrements the .length. So let's rewrite it to:

sayHi(1, 2, 3);
function sayHi(x,y,z) {
/*  var x = 1,
        y = 2,
        z = 3,
    arguments = {
        get 0() { return x }, set 0(v) { x = v },
        get 1() { return y }, set 1(v) { y = v },
        get 2() { return z }, set 2(v) { z = v },
        length: 3
    }
*/
    //  variables   arguments
    //  x   y   z  [0] [1] [2] length
    //  1   2   3   1   2   3   3

    // [].shift.call(arguments):
    arguments[0] = arguments[1]; arguments[1] = arguments[2]; delete arguments[2]; arguments.length--;
//  x = 2;                       y = 3;
    //  2   3   3   2   3   -   2

    [].shift.call(arguments);
    // [].shift.call(arguments):
    arguments[0] = arguments[1]; delete arguments[1]; arguments.length--;
//  x = 3;
    //  3   3   3   3   -   -   1

    // [].shift.call(arguments):
    delete arguments[0]; arguments.length--;
//  ;
    //  3   3   3   -   -   -   0
}

As you see, when shift reassigns the indices of arguments (and invokes the setter), this is reflected in the respective parameter variables. However, when you delete a property, the setter is not invoked, and the variables are not modified - you cannot "undeclare" a variable anyway.

2
  • thx, but you didn't tell me why x,y,z becomes 1,2,3 -> 3,3,3? As arguments[0],arguments[1],arguments[2] is - - -, then why x,y,z is 3,3,3??? Commented Nov 5, 2014 at 10:58
  • 1
    Because when arguments properties are deleted, the variables are not modified - the setter property is not invoked. If shift would have assigned undefined instead or so, then the variables would reflect that.
    – Bergi
    Commented Nov 5, 2014 at 13:36
0

This only works without strict mode:

function test(x, y) {
  console.log("Original: " + x); // 1
  [].shift.apply(arguments);
  console.log("Modified: " + x); // 2
}

function testStrict(x, y) {
  "use strict"
  console.log("Original (strict): " + x); // 1
  [].shift.apply(arguments);
  console.log("Modified (strict): " + x); // 1
} 


test(1,2)
testStrict(1,2)

http://jsfiddle.net/omahlama/mmn2vf0p/

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.