javascript传递对象作为参考
Posted
技术标签:
【中文标题】javascript传递对象作为参考【英文标题】:javascript pass object as reference 【发布时间】:2013-05-28 15:22:20 【问题描述】:我有一个对象,它在函数内的许多不同函数中传递。这些函数可能会也可能不会改变对象的值,但如果他们确实改变了它,那么我想获得对象的最新更改。
以下是我想要做的:
var ob = text: 'this is me', name: 'john'
function (object)
changeObject(object);
customObjectChanger(object);
callback = function (object)
object.text = 'new text';
callback(object);
// object value here should be objecttext: 'new text', name: 'john';
【问题讨论】:
javascript 一直自动通过引用传递对象。您是否尝试过上面的代码,看看它是否已经完成了您想要的操作? 不,我没有。我确实读过它。只是想在这里确认一下。 JavaScript 不 Pass By Reference。但是,JavaScript在对象被传递或分配时不会复制对象。因此,它是具有不同名称的 same 对象 - 对对象所做的更改(从任何名称)都会影响所述对象。 这取决于您所说的“通过引用”。在我看来,“同一个对象,不同的名字”就是引用的定义。 @jcsanyi 这就是为什么定义术语和避免歧义很重要。 (***的文章确实承认该术语是模棱两可的,这就是为什么我尝试避免使用“通过引用”,除非明确意味着更改本地名称绑定会影响调用者。) 【参考方案1】:在 JavaScript 中,对象总是通过复制引用传递。我不确定这是否是完全正确的术语,但会传入对象引用的副本。
这意味着对对象所做的任何更改都将在函数执行完成后对您可见。
代码:
var obj =
a: "hello"
;
function modify(o)
o.a += " world";
modify(obj);
console.log(obj.a); //prints "hello world"
话虽如此,由于它只是传入的引用的副本,如果您重新分配函数内部的对象,这将在函数之外不可见,因为它只是您更改的引用的副本。
代码:
var obj =
a: "hello"
;
function modify(o)
o =
a: "hello world"
;
modify(obj);
console.log(obj.a); //prints just "hello"
【讨论】:
en.wikipedia.org/wiki/Evaluation_strategy - 我更喜欢“通过 [对象] 共享调用”,因为它的直接性、实现关注点的分离以及减少与其他调用约定的歧义。 ECMAScript 在规范的任何部分不为此目的使用“参考”。 (参考规范类型不适用于函数调用。) +1 可以清楚地描述与传统传递引用的不同之处。 我想我已经明确传递了对象引用的副本,而不是对象本身。 我该如何处理这个问题?如果我想更改对象本身而不是其复制引用怎么办? @Abhinav1602 我想在函数中重新分配一个对象,它的新值在调用函数中可见。【参考方案2】:“对象”不是 JavaScript 中的值,不能“通过”。
您处理的所有值都是引用(指向对象的指针)。
传递或分配一个引用会给出另一个指向同一个对象的引用。当然,您可以通过其他引用修改同一个对象。
【讨论】:
确实——所以对对象的引用的副本是...“通过”-_- 确实不会传递对象,但会传递引用,如果在接收器函数内部更改属性,您可以修改其属性 简单、简洁的答案。将对象分配给变量时,分配的值是对该对象的引用。所以所有变量都有一个值,但有些值是对对象的引用(例如对象、函数、数组),有些是字面量(例如数字、字符串、布尔值和其他原语)。【参考方案3】:这是对按值传递和按引用传递 (Javascript) 的更多解释。 在这个概念中,他们谈论的是通过引用传递变量和通过引用传递变量。
按值传递(原始类型)
var a = 3;
var b = a;
console.log(a); // a = 3
console.log(b); // b = 3
a=4;
console.log(a); // a = 4
console.log(b); // b = 3
适用于 JS 中的所有基本类型(字符串、数字、布尔值、未定义、空值)。
a
被分配了一个内存(比如 0x001),b
在内存中创建一个值的副本(比如 0x002)。
因此更改变量的值不会影响另一个变量,因为它们都位于两个不同的位置。
通过引用传递(对象)
var c = "name" : "john" ;
var d = c;
console.log(c); // "name" : "john"
console.log(d); // "name" : "john"
c.name = "doe";
console.log(c); // "name" : "doe"
console.log(d); // "name" : "doe"
JS 引擎将对象分配给变量c
,它指向一些内存,比如(0x012)
当d=c
时,在这一步中d指向同一个位置(0x012)。
更改两个变量的任何更改值。
函数就是对象
特殊情况,通过引用传递(对象)
c = "name" : "jane";
console.log(c); // "name" : "jane"
console.log(d); // "name" : "doe"
equal(=
) 运算符设置新的内存空间或地址
【讨论】:
【参考方案4】:基本上,在 JavaScript 中,没有 Pass-By-Reference 的概念,因为 Pass-by-value 服务于使 JS 如此特别的目的。当我们在 JavaScript 中传递一个对象时, 1)函数需要带有值,并且该值是参考副本 2)这个值是原始对象的地址。
【讨论】:
【参考方案5】:我该如何处理这个问题?如果我想更改对象本身而不是其复制引用怎么办?
我想在函数中重新分配一个对象,并且它的新值在调用函数中可见。
为了增加公认的答案,并在那里解决 cmets 中未回答的问题,以下是我对通过参考传递的看法,并在实践中查看 scope / closure:
const obj =
count: 0,
function incrementReference(_obj)
obj.count++
function createIncrementByCopy(_obj)
let inner =
Object.assign(inner, _obj)
return function increment()
inner.count++
function createScopedIncrement(_obj)
return function increment()
_obj.count++
function createExtend(_obj)
return function increment(ext)
Object.assign(_obj, ext)
console.log('obj', obj) // count: 0
incrementReference(obj)
console.log('incrementReference ✅', obj.count) // 1
const incrementCopy = createIncrementByCopy(obj)
incrementCopy()
console.log('incrementCopy ❌', obj.count) // 1
const incrementA = createScopedIncrement(obj)
incrementA()
console.log('incrementA ✅', obj.count) // 2
const extendObj = createExtend(obj)
extendObj( text: 'New Property!' )
console.log('extendObj ✅', obj) // count: 2, text: 'New Property!'
下面的文章讨论了一个关于术语的常见混淆,我真的无话可说?https://dev.to/bytebodger/a-gotcha-of-javascript-s-pass-by-reference-1afm
相关(良好的上下文,更复杂,不同的用例):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#copying_accessors
【讨论】:
以上是关于javascript传递对象作为参考的主要内容,如果未能解决你的问题,请参考以下文章
在 Symfony2 中使用 Twig 作为 JavaScript 的资产过滤器