The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
How Ext.apply works, and how to avoid a big headache

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Edward Spencer

Posts: 148
Nickname: edspencer
Registered: Aug, 2008

Edward Spencer is a Ruby/Rails developer and the creator of the ExtJS MVC framework
How Ext.apply works, and how to avoid a big headache Posted: Aug 27, 2008 11:39 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Edward Spencer.
Original Post: How Ext.apply works, and how to avoid a big headache
Feed Title: Ed's Elite blog
Feed URL: http://feeds2.feedburner.com/EdSpencer
Feed Description: Ruby on Rails development, Git issues and ExtJS/JavaScript
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Edward Spencer
Latest Posts From Ed's Elite blog

Advertisement
Ext.apply is one of those magic Ext JS methods which copies the essence of one object onto another. You usually call it like this:

Ext.apply(receivingObject, sendingObject, defaults)

Where defaults are optional. If you supply defaults, Ext.apply actually does this:

Ext.apply(receivingObject, defaults);
Ext.apply(receivingObject, sendingObject);

In other words, the order of precedence of the three arguments goes like this: any properties in receivingObject which are also present in defaults will be overwritten by the property in defaults. After that has happened, any properties which are present receivingObject (after defaults have been applied) and also present in sendingObject will be overwritten by the sendingObject value. More graphically:

Ext.apply({a: 'receiver'}, {a: 'sender'}, {a: 'default'}); // = {a: 'sender'}

For me, this was slightly unexpected as I expected the default options to have the lowest priority - that is the default option would only be copied across if it was not present in either the receiving or the sending objects, so watch out for that.

Anyway that's all well and good once you know how it works inside, but while watching an otherwise excellent screencast from Jay Garcia (see http://tdg-i.com/42/ext-js-screencast-003-extapply-published), something odd happened. The example he gave went like this (commented lines signify the output returned by Firebug):


var obj1 = {x: 'x string', y: 'y string'}
// = {x: 'x string', y: 'y string'}

var obj2 = {a: 'a string', b: 4289, c: function(){}}
// = {a: 'a string', b: 4289, c: function(){}}

var obj3 = Ext.apply(obj2, obj1, {pxyz: 'soifje'})
obj3
// = {a: 'a string', b: 4289, pxyz: 'soifje', x: 'x string', y: 'y string'}
obj2
// = {a: 'a string', b: 4289, pxyz: 'soifje', x: 'x string', y: 'y string'}
obj3 === obj2
// true - obj3 and obj2 are the same object

var obj4 = Ext.apply(obj3, obj2, {a: 'fwaifewfaije'})
// obj4 = {a: 'fwaifewfaije', b: 4289, pxyz: 'soifje', x: 'x string', y: 'y string'}

So basically he set up obj1 and obj2 with non-conflicting properties, then merged them with some defaults to create obj3. In this case the defaults didn't conflict with the properties from obj1 or obj2, so obj3 is essentially a straightforward combination of obj1 and obj2, plus a default pxyz value.

What he did then however was to create obj4 as a combination of obj2 and obj3, along with a default value for the 'a' property, which was a property of obj2 and obj3. Crucially, obj4's 'a' property was set to the default value, which as we've seen from how Ext.apply works above, should never happen (it should be set to the default value but then immediately set back again on the second internal Ext.apply call).

So what gives? Well, it turns out this is because when calling:

obj3 = Ext.apply(obj2, obj1, {pxyz: 'soifje'})

obj3 and obj2 are the exact same object, as Ext.apply returns the first argument after the apply process has taken place. So in the next call:

obj4 = Ext.apply(obj3, obj2, {a: 'fwaifewfaije'})

obj3 and obj2 are in fact both references to the same object, which is causing the unexpected default value. We can show this by manually creating a new obj3 with the exact same properties, and running the example again:

var obj1 = {x: 'x string', y: 'y string'}
// obj1 = {x: 'x string', y: 'y string'}

var obj2 = {a: 'a string', b: 4289, c: function(){}}
// obj2 = {a: 'a string', b: 4289, c: function(){}}

var obj3 = {a: 'a string', b: 4289, pxyz: 'soifje', x: 'x string', y: 'y string'}
// obj2 = {a: 'a string', b: 4289, pxyz: 'soifje', x: 'x string', y: 'y string'}
// obj3 === obj2 => false... obj3 and obj2 are the same object

var obj4 = Ext.apply(obj3, obj2, {a: 'fwaifewfaije'})
// obj4 = {a: 'a string', b: 4289, pxyz: 'soifje', x: 'x string', y: 'y string'}

This time around we get what we expect - the default value is not applied because it is already present in obj2. Here, obj2 is not the same object as obj3, even though their properties are identical.

I'm not completely certain why two references to the same object cause this behaviour, but the code above does appear to demonstrate that this is what is happening (you can just copy/paste each example into Firebug to reproduce it).

Moral of the story? Well, now you have a more detailed understanding of Ext.apply, and hopefully you'll be on your guard about referencing the same object by two different variables when performing this type of operation. I know I will be ;)

Read: How Ext.apply works, and how to avoid a big headache

Topic: Sometimes More is Just Enough Previous Topic   Next Topic Topic: Some functional programming and OCaml koans

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use