Scope in javascript acting weird

前端 未结 6 1298
悲哀的现实
悲哀的现实 2021-02-18 18:47

Object are passed with their reference in javascript. Meaning change in that object from any where should be reflected. In this case, the expected output was {} for console.log(

相关标签:
6条回答
  • 2021-02-18 18:59

    Okay, so you've figured out that JavaScript objects have reference semantics, so modifying a referent has an effect on the same object in the original scope.

    What you also need to realise is that = is not part of these rules; not only does it perform assignment, but it will also rebind the reference to a new object.

    Under the hood, so to speak, that's basically how your original references were formed.

    0 讨论(0)
  • 2021-02-18 19:04

    The variable 'a' in the context of your function is not the same as the 'a' variable outside the function. This code is semantically equivalent to yours:

    function change(foo,bar) {
        foo.x = 'added';
        foo = bar;//assigning foo as {} to bar
    }
    a={}
    b={}
    change(a,b);
    console.log(a); //expected {} but output {x:'added'}
    console.log(b)
    

    It's obvious in this case that the 'foo' variable only exists inside the function, and doing foo = bar doesn't change a as the reference is passed by value.

    0 讨论(0)
  • 2021-02-18 19:13

    This should help to solve your problem:

    var obj = {}, anotherObj = {};
    // in case if they are not global, make them global or define parent scope to be able to modify inside the function
    window.obj = obj;
    window.anotherObj = anotherObj;
    function swap(a, b) {
      window[a].newProp = 'XYZ';
      window[a] = window[b]; // now obj is gone, because replaced with anotherObj
    }
    swap('obj','anotherObj');
    console.log(obj); // now it would give Object {}
    
    0 讨论(0)
  • 2021-02-18 19:16

    You are right that objects are passed by reference and any change made to the object in the function will be reflected everywhere. This is precisely why adding the x property in the function modified the object outside of it.

    What you are missing is that the line a = b; does not modify the object, it modifies the reference to the object. You can pass both of the objects in another container object / array if you need to set the reference:

    function change(container) {
        container.a.x = 'added';
        container.a = container.b;//assigning a as {} to b
    }
    var container = { a: {}, b: {}};
    change(container);
    console.log(container.a);
    console.log(container.b)
    
    0 讨论(0)
  • 2021-02-18 19:16

    Object are passed with their reference in javascript.

    No, they aren't. ECMAScript/JavaScript is strictly pass-by-value. (More precisely, call-by-sharing, which is a special case of pass-by-value.)

    What is happening here?

    This is just normal pass-by-value.

    Your confusion stems from the fact that you erroneously believe ECMAScript/JavaScript is pass-by-reference, when in fact it is not.

    ECMAScript uses pass-by-value, or more precisely, a special case of pass-by-value where the value being passed is always a pointer. This special case is also sometimes known as call-by-sharing, call-by-object-sharing or call-by-object.

    It's the same convention that is used by Java (for objects), C# (by default for reference types), Smalltalk, Python, Ruby and more or less every object-oriented language ever created.

    Note: some types (e.g. Numbers) are actually passed directly by value and not with an intermediary pointer. However, since those are immutable, there is no observable behavioral difference between pass-by-value and call-by-object-sharing in this case, so you can greatly simplify your mental model by simply treating everything as call-by-object-sharing. Just interpret these special cases as internal compiler optimizations that you don't need to worry about.

    Here's a simple example you can run to determine the argument passing convention of ECMAScript (or any other language, after you translate it):

    function isEcmascriptPassByValue(foo) {
      foo.push('More precisely, it is call-by-object-sharing!');
      foo = 'No, ECMAScript is pass-by-reference.';
      return;
    }
    
    var bar = ['Yes, of course, ECMAScript *is* pass-by-value!'];
    
    isEcmascriptPassByValue(bar);
    
    console.log(bar);
    // Yes, of course, ECMAScript *is* pass-by-value!,
    // More precisely, it is call-by-object-sharing!

    If you are familiar with C#, it is a very good way to understand the differences between pass-by-value and pass-by-reference for value types and reference types, because C# supports all 4 combinations: pass-by-value for value types ("traditional pass-by-value"), pass-by-value for reference types (call-by-sharing, call-by-object, call-by-object-sharing as in ECMAScript), pass-by-reference for reference types, and pass-by-reference for value types.

    (Actually, even if you don't know C#, this isn't too hard to follow.)

    // In C#, struct defines a value type, class defines a reference type
    struct MutableCell
    {
        public string value;
    }
    
    class Program
    {
        // the ref keyword means pass-by-reference, otherwise it's pass-by-value
        // You must explicitly request pass-by-reference both at the definition and the call
        static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
        {
            foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
            foo = new string[] { "C# is not pass-by-reference." };
    
            bar.value = "For value types, it is *not* call-by-sharing.";
            bar = new MutableCell { value = "And also not pass-by-reference." };
    
            baz = "It also supports pass-by-reference if explicitly requested.";
    
            qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
        }
    
        static void Main(string[] args)
        {
            var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
    
            var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
    
            var grault = "This string will vanish because of pass-by-reference.";
    
            var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
    
            // the first two are passed by value, the other two by reference
            IsCSharpPassByValue(quux, corge, ref grault, ref garply);
    
            Console.WriteLine(quux[0]);
            // More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
    
            Console.WriteLine(corge.value);
            // For value types it is pure pass-by-value.
    
            Console.WriteLine(grault);
            // It also supports pass-by-reference if explicitly requested.
    
            Console.WriteLine(garply.value);
            // Pass-by-reference is supported for value types as well.
        }
    }
    
    0 讨论(0)
  • 2021-02-18 19:22

    If you added another line you can get a clearer picture of what is happening:

    function change(a,b) {
        a.x = 'added';
        a = b;
        a.x = 'added as well';
    };
    a={};
    b={};
    change(a,b);
    console.log(a);  //{x:'added'}
    console.log(b);  //{x:'added as well'}
    

    When you're doing a = b you're assigning the local variable a to the reference that b is holding.

    0 讨论(0)
提交回复
热议问题