26

我在函数外部定义了一个对象,在全局范围内。该对象不作为参数传递给函数,但函数会修改它并返回修改后的对象。

我想知道的是,如果函数返回对象的副本,还是原始的全局对象?

另外,将该对象作为参数传递给函数会有所不同,因为对象是通过引用传递给函数的吗?

4

5 回答 5

57

每当您返回一个对象时,您就是在返回对该对象的引用。同样,当你传递一个对象时,你传递的是一个引用。但是,将对象作为参数传入可能与仅在全局范围内更改对象不同,如这些示例所示。这是因为对对象的引用本身是按值传递的。

如果您要更改对象的成员,那么无论是将其作为参数传入还是仅更新全局对象都没有区别。无论哪种方式,您都在使用同一个对象。

示例 1:

var object = {foo:'original'};

function changeObject() {
    object.foo = 'changed';
    return object;
}

console.log(changeObject()); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}

示例 2:

var object = {foo:'original'};

function changeArgument(object) {
    object.foo = 'changed';
    return object;
}

console.log(changeArgument(object));  // outputs {foo:'changed'}
console.log(object);  // outputs {foo:'changed'}

另一方面,如果您使用新对象覆盖该对象,则如果您对参数执行此更改将不会持续存在,但如果您对全局对象执行此更改将持续存在。那是因为参数按值传递对对象的引用。一旦你用一个新对象的引用替换了这个值,你就不再谈论同一个对象了。

示例 3:

var object = {foo:'original'};

function replaceObject() {
    object = {foo:'changed'};
    return object;
}

console.log(replaceObject()); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'changed'}

示例 4:

var object = {foo:'original'};

function replaceArgument(object) {
    object = {foo:'changed'};
    return object;
}

console.log(replaceArgument(object)); // outputs {foo:'changed'}
console.log(object); // outputs {foo:'original'}
于 2013-02-21T16:03:33.360 回答
3

可能是迟到的评论,但这是任何语言的典型挑战。在堆上创建并通过引用而不是原语(按值)传递的对象。我认为问题的根源是共享实例与唯一实例,以避免不受欢迎的影响。例如,我们调用一个函数来获取一个模板(对象)以供新用户添加到集合中,或者想要清除来自不同模块的取消事件的表单以重新开始。它易于理解且易于忽略..测试用例通常不涵盖所有使用排列

健全性清单:

这里是共享实例:

var bigo = {
    usr: { name: 'steven' },
    bigi: function () {
        return this.usr;
    }
};   
var outA = bigo.bigi();
var outB = bigo.bigi();

print(outA.name); // => steven
print(outB.name); // => steven

outA.name = 'ilan'; // change value

print(outA.name); // => ilan
print(outB.name); // => ilan

非共享实例:

var bigo = {
    bigi: function () {
        var user = { name: 'steven' };
        return user;
    }
};   

var outA = bigo.bigi();
var outB = bigo.bigi();

print(outA.name); // => steven
print(outB.name); // => steven

outA.name = 'ilan'; // change value

print(outA.name); // => ilan
print(outB.name); // => steven
于 2017-10-07T16:09:43.330 回答
1

我想知道的是,如果函数返回对象的副本,还是原始的全局对象?

实际上,您只需要在 JavaScript 中处理对对象的引用。甚至var foo = {}只是将新对象的引用分配给foo.

于 2013-02-21T15:43:20.573 回答
1

如果对象在函数之外,则不需要“返回”它。如果您在函数中修改对象,它将更新对象本身。然后您可以根据需要在其他函数中引用新更新的对象。

于 2013-02-21T15:44:16.093 回答
1

从您的问题来看,这就是我认为您的代码的外观(或多或少):

var o = {};

function f() {
    o.prop = true;
    return o;
}
  1. 在这种情况下,全局变量o引用一个对象。
  2. 当你修改o你修改任何o引用。因此它修改了原始对象。
  3. 当您返回时,o您将返回对原始对象的引用。

将对象传递给函数会导致对原始对象的引用被传递。因此,任何修改都会影响原始对象。例如:

var o = {};

f(o);

console.log(o.prop); // true

function f(o) {
    o.prop = true;
}
于 2013-02-21T15:56:54.617 回答