簡體   English   中英

javascript中的范圍很奇怪

[英]Scope in javascript acting weird

在javascript中傳遞對象及其引用。 意味着應該反映任何地方對象的變化。 在這種情況下,console.log(a)的預期輸出為{}

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

這里發生了什么? 據我所知,這不應該是因為功能范圍。 謝謝

如果您添加了另一行,您可以更清楚地了解正在發生的事情:

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'}

當您執行a = b您將局部變量a分配給b所持有的引用。

你是對的,通過引用傳遞對象,並且對函數中的對象所做的任何更改都將反映在任何地方。 這正是為什么在函數中添加x屬性修改了它之外的對象的原因。

你缺少的是a = b; 不修改對象 ,它修改對象引用 如果需要設置引用,可以傳遞另一個容器對象/數組中的兩個對象:

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)

函數上下文中的變量“a”與函數外部的“a”變量不同。 此代碼在語義上等同於您的代碼:

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)

在這種情況下很明顯,'foo'變量只存在於函數內部,而foo = bar不會改變a因為引用是按值傳遞的。

在javascript中傳遞對象及其引用。

不,他們不是。 ECMAScript / JavaScript嚴格按值傳遞。 (更准確地說,是分享呼叫,這是傳遞值的特殊情況。)

這里發生了什么?

這只是正常的傳值。

您的困惑源於您錯誤地認為ECMAScript / JavaScript是傳遞引​​用的事實,而實際上並非如此。

ECMAScript使用pass-by-value,或者更確切地說,是一個傳遞值的特殊情況,其中傳遞的值始終是指針。 這種特殊情況有時也稱為共享呼叫,對象共享呼叫或逐個呼叫。

它與Java(用於對象),C#(默認情況下用於引用類型),Smalltalk,Python,Ruby以及或多或少的所有面向對象語言所使用的約定相同。

注意:某些類型(例如Number s)實際上是通過值直接傳遞的,而不是通過中間指針傳遞的。 但是,由於這些是不可變的,在這種情況下,傳值和逐個對象共享之間沒有可觀察到的行為差異,因此您可以通過簡單地將所有內容視為逐個對象來大大簡化您的心智模型。分享。 只需將這些特殊情況解釋為內部編譯器優化,您無需擔心。

這是一個簡單的例子,您可以運行以確定傳遞ECMAScript(或任何其他語言,翻譯后)約定的參數:

 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! 

如果您熟悉C#,那么理解值類型和引用類型的pass-by-value和pass-by-reference之間的差異是一種非常好的方法,因為C#支持所有4種組合:value for value-value for value types(“傳統的按值傳遞”),引用類型的值傳遞(按共享調用,按對象調用,在ECMAScript中按對象分享),傳遞引用用於引用類型,以及值類型的傳遞引用。

(其實,即使你知道C#,這是不是太難懂了。)

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

好的,所以你已經發現JavaScript對象具有引用語義,因此修改引用對原始范圍中的同一對象有影響。

你還需要意識到的是=不是這些規則的一部分; 它不僅執行賦值,還會重新綁定對新對象的引用。

可以這么說,這基本上就是你原始參考文獻的形成方式。

這應該有助於解決您的問題:

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 {}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM