Question

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?

Was it helpful?

Solution

What you basically have at first is an object and a variable referencing it:

enter image description here

What you're then doing is setting another variable to the same object:

enter image description here

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:

enter image description here

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top