How does javascript x = y work when dealing with objects?
I am working with Omniture tagging and I've got numerous events on the page. In omniture, the base object is s
this object is created globally by Omniture.
The s
object has a number of "standard" variables that I like to set for it, url, pagetitle, time on site, what have you...
For each event I set one or two additional properties
I thought I was being really clever in writing functions like:
// s is a global variable create by omniture
function ClickFoo(){
var s_ = s; // make a copy of s which has all the standard vars
s_.event = "Click Foo"; // set X number of custom vars
s_.prop1 = "foo";
s_.t(); // the Omniture "submit event" function
}
function ClickBar(){
var s_ = s;
s_.event = "Click Bar";
s_.prop2 = "bar";
s_.t();
}
ClickFoo();
ClickBar();
// at this point, s.prop1 = "foo"
If the user clicks foo
then bar
the s_.prop1
object property is set on the bar submit.
I've been looking at the behavior of this stuff in the JS console and it seems that changes to s_ have an effect on the global object s.
Can anyone explain how the assignment is working so I don't make this开发者_开发技巧 mistake in future? Is there a quick way to do this correctly?
What you basically have at first is an object and a variable referencing it:
What you're then doing is setting another variable to the same object:
So when altering _s
, you're dealing with the exact same object as s
and hence you get those altered values with s
as well.
Instead, you want two different objects, basically clones:
There are several clone snippets available. In jQuery, it's as easy as $.extend({}, obj)
, and in vanilla JavaScript this one can be used for example.
var _s = s;
is not copying s
, but makes both _s
and s
reference the same object. You will need to either create a new object or copy the properties of the original object into _s. There are clone methods you could use:
Object.prototype.clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (i in this) {
if (i == 'clone') continue;
if (this[i] && typeof this[i] == "object") {
newObj[i] = this[i].clone();
} else newObj[i] = this[i]
} return newObj;
};
...
var _s = s.clone(); // _s now does not reference the same object as s
When you assign an object to a variable, the reference to the variable is copied. The object is not "cloned" in any way. So:
var a = {},
b = a;
b.foo = 'bar';
alert(a.foo); // 'bar'
This is intentional behaviour. (As a side point, the only time when a == b
if a
and b
are objects is if they are references to the same object.)
If you want to deliberately clone an object, it's a little trickier. If you have a modern browser, you can use Object.create
to clone an object effectively:
var a = {},
b = Object.create(a);
b.foo = 'bar';
alert(a.foo); // undefined
You can patch this behaviour into your application by using the method in that MDN page:
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the first parameter.');
}
function F() {}
F.prototype = o;
return new F();
};
}
From MDN
So if you use this code, you could then do this at the top of your methods:
var s_ = Object.create(s);
You would then be working on separate objects and the problems you found would not happen.
Think of references being decoupled from objects.
_s and s are both references. In the statement,
var _s = s;
you are copying the referenced value in s to _s. So they now refer to the same object.
精彩评论