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

Sign up to request clarification or add additional context in comments.

2 Comments

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???
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.
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/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.