Why does an unexecuted eval have an effect on behavior in some browsers?

前端 未结 3 1164
死守一世寂寞
死守一世寂寞 2020-12-24 14:02

Let\'s suppose I have these two functions:

function change(args) {
    args[0] = \"changed\";
    return \" => \";
}
function f(x) {
    return [x, change         


        
3条回答
  •  再見小時候
    2020-12-24 14:13

    Here's some excellent Javascript nuances coming into effect:

    change(f.arguments)
    change(x)
    

    The former passes the argument list into change() as a reference. Arrays tend to be references in Javascript. This means that if you change an element of an array somewhere else, those changes will be applied wherever you use that same array.

    The latter passes the argument x as a value. It's like handing off a copy - change can change it around and it will only affect the local variable. Because x is a string, and strings are immutable, args[0] = "changed" in the change() function doesn't do anything. Try the following in a console:

    var x = "asdf";
    x[0] = "foo";
    console.log(x); // should print "asdf"
    

    In the f, h, g functions, the value of arguments[0] is changed in the second index in the returned list. The third index will return "changed".

    Theoretically. However, some browsers compile Javascript, which causes kind-of race conditions and instructions may not execute in the order you type them, especially if they are on the same line and you're changing the stack and accessing it from the same line.

    return [x, change(f.arguments), x];
    

    ...attempts to change the arguments variable and access x (which is an argument) at the same time. In Chrome, for instance, passing f.arguments to change() results in ["original", " => ", "original"] while passing just arguments results in ["original", " => ", "changed"]. It may also be a scoping issue and how Javascript handles value and reference types, but that behaviour is different across browsers.

    I didn't see any odd behaviour with eval() given what I've described, but it seems that stating arguments in the h() function after the return creates a side-effect that I suspect is caused by Chrome's compilation of Javascript. What's really interesting is that internally, the shell executes a variable by returning its value, but it's not being written anywhere, expect perhaps to a cache. Hard to tell what's going on in Javascript's stack, but what you're doing is certainly unconventional and it will for sure mess up the compiler across browsers.

    EDIT:

    Even better: console.log(h.arguments); return [x, change(arguments), x]; arguments

    will log

    ["changed"]
    ["original", " => ", "changed"]
    

    Sure looks like a race condition, or some wonky passing of references to the arguments array within functions!

提交回复
热议问题