Prev: how to get url of script
Next: question of logic?
From: JJ on 18 Mar 2010 08:25 Hi all I wanted to ask a question about below code I found in a Javascript file: [---SNIP---] // Action Constants function Action() {} // Action types, Action names Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 }; Action.Name = [ "add.web", "save.web", "close" ]; ....(continued)... function getActionType( iTxnCode, sStatus ) { var iActionType; switch( iTxnCode ) { case DwngTxn.TpisTxCode.INCIDENT_SUBMITTAL: if( !sStatus ) iActionType = Action.Type.ADD; else iActionType = Action.Type.UPDATE; break; ....(continued)... [---SNIP---] The question is that the person who developed above code seems to be creating a function like an object (correct me if I am wrong) and then giving it two array(?) attributes "Type" and "Name" which he/she then populates with values. Later in the code he/she then refers to these in the expressions: iActionType = Action.Type.ADD; ....and... iActionType = Action.Type.UPDATE; My question is about that I have tried to find more information on the web about doing this but have not seen much of anything. Could anyone give me a brief description of what is going on above and what the benefits of above is (or is it just to keep the code clean)? Thanks in advance,
From: Thomas 'PointedEars' Lahn on 18 Mar 2010 08:49 JJ wrote: > // Action Constants > function Action() {} > // Action types, Action names > Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 }; > Action.Name = [ "add.web", "save.web", "close" ]; Note that those are not real constants, but currently there is no better interoperable way. > [...] > if( !sStatus ) > iActionType = Action.Type.ADD; > else > iActionType = Action.Type.UPDATE; Can (and IMHO should) be written as follows: var iActionType = (sStatus) ? Action.Type.UPDATE : Action.Type.ADD; > [...] > > The question is that the person who developed above code seems to be > creating a function like an object (correct me if I am wrong) Functions *are* first-class objects in ECMAScript implementations, with a double meaning of "object" here. > and then giving it two array(?) attributes "Type" and "Name" which he/she > then populates with values. No, that Function instance is augmented with two _properties_, one storing a reference to an Object instance (initialized with `{'...`}') and the other storing a reference to an Array instance (initialized with `['...`]'). (JavaScript != Java) > Later in the code he/she then refers to these in the expressions: > iActionType = Action.Type.ADD; > ...and... > iActionType = Action.Type.UPDATE; > > My question is about that I have tried to find more information on the > web about doing this but have not seen much of anything. It really is not much of a mystery if you know that functions are objects. > Could anyone give me a brief description of what is going on above and > what the benefits of above is (or is it just to keep the code clean)? Yes, using an object as if it was a namespace is a way to keep the global context clean. The Global Object would then have only one user-defined property, not several. However, the function here is a waste of resources if it is never called; in that case var Action = { Type: { ADD: 0, UPDATE: 1, CLOSE: 2 }; Name: [ "add.web", "save.web", "close" ]; }; would have sufficed. In any way the property names of the "non-constants" should have started lowercase as they do not denote constructors, i.e. `Action.type.ADD' or even `action.type.ADD'. PointedEars -- Use any version of Microsoft Frontpage to create your site. (This won't prevent people from viewing your source, but no one will want to steal it.) -- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
From: David Mark on 18 Mar 2010 08:48 JJ wrote: > Hi all > > I wanted to ask a question about below code I found in a Javascript > file: > > [---SNIP---] > // Action Constants > function Action() {} > // Action types, Action names > Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 }; > Action.Name = [ "add.web", "save.web", "close" ]; > > ...(continued)... Appears to be a botched attempt at writing a constructor. I assume they call this (once) at some point. They should have just used an object literal:- var action = { type : { ADD: 0, UPDATE: 1, CLOSE: 2 }, name : [ "add.web", "save.web", "close" ] }; > > function getActionType( iTxnCode, sStatus ) > { > var iActionType; > switch( iTxnCode ) { > case DwngTxn.TpisTxCode.INCIDENT_SUBMITTAL: > if( !sStatus ) > iActionType = Action.Type.ADD; > else > iActionType = Action.Type.UPDATE; > break; > > ...(continued)... > [---SNIP---] > > > The question is that the person who developed above code seems to be > creating a function like an object (correct me if I am wrong) and then > giving it two array(?) attributes "Type" and "Name" which he/she then > populates with values. Functions _are_ objects, though using them in lieu of an Object object (as is the case here) is not a sound practice. > > Later in the code he/she then refers to these in the expressions: > iActionType = Action.Type.ADD; > ...and... > iActionType = Action.Type.UPDATE; > > > > My question is about that I have tried to find more information on the > web about doing this but have not seen much of anything. Could anyone > give me a brief description of what is going on above and what the > benefits of above is (or is it just to keep the code clean)? No benefits (just confusion). It's simply another bad JS example (the Web is crawling with them).
From: Thomas 'PointedEars' Lahn on 18 Mar 2010 09:32 David Mark wrote: > JJ wrote: >> The question is that the person who developed above code seems to be >> creating a function like an object (correct me if I am wrong) and then >> giving it two array(?) attributes "Type" and "Name" which he/she then >> populates with values. > > Functions _are_ objects, No doubt about that. > though using them in lieu of an Object object > (as is the case here) is not a sound practice. IBTD. We do not know whether Action() is ever called, and properties on constructors and functions in general can be a powerful tool. For example, I am using it in my Map implementation as follows: /** * Returns <code>true</code> if the argument is a {@link Map} * * @param o : Object * @return boolean */ Map.isInstance = function (o) { return !!o && o.constructor === this; }; PointedEars -- Anyone who slaps a 'this page is best viewed with Browser X' label on a Web page appears to be yearning for the bad old days, before the Web, when you had very little chance of reading a document written on another computer, another word processor, or another network. -- Tim Berners-Lee
From: David Mark on 18 Mar 2010 09:56
Thomas 'PointedEars' Lahn wrote: > David Mark wrote: > >> JJ wrote: >>> The question is that the person who developed above code seems to be >>> creating a function like an object (correct me if I am wrong) and then >>> giving it two array(?) attributes "Type" and "Name" which he/she then >>> populates with values. >> Functions _are_ objects, > > No doubt about that. > >> though using them in lieu of an Object object >> (as is the case here) is not a sound practice. > > IBTD. We do not know whether Action() is ever called, Ack. I misread partial paste as:- function Action() { // Action types, Action names Action.Type = { ADD: 0, UPDATE: 1, CLOSE: 2 }; Action.Name = [ "add.web", "save.web", "close" ]; ....(continued)... Which would seem to imply a botched constructor. I suppose if it were a lowercase, then the only complaint is the (seemingly) inexplicable use of a Function object where an Object object would be more appropriate. > and properties on > constructors and functions in general can be a powerful tool. Sometimes, but this doesn't look like one of those times. > For example, > I am using it in my Map implementation as follows: > > /** > * Returns <code>true</code> if the argument is a {@link Map} > * > * @param o : Object > * @return boolean > */ > Map.isInstance = function (o) { > return !!o && o.constructor === this; > }; I would lose the truthy test and document that this method accepts objects only. If passed undefined (or whatever), it _should_ throw an exception, rather than fail silently as, in such a case, there is clearly something wrong with the calling code (and the author should best be advised of it). Consider these two (incorrect) calls of API.isOwnProperty:- API.isOwnProperty(undefined, 'someproperty'); // exception API.isOwnProperty(someObject, 'somenonexistentproperty'); // true ....and granted, the results may _appear_ to be mistakes in the library, but the unforgiving nature is fully intended (and definitely more useful than glossing over obvious mix-ups in the calling code). From the docs:- "The isOwnProperty function tests if the specified object does not inherit the specified property from its prototype. The property is stipulated to exist. This function is typically used to filter inherited properties within for-in loops. Note the object must be native, not a host object." For example, the method is meant to be used in this fashion:- for (var i in o) { if (API.isOwnProperty(o, i)) { // Do something with o[i] } } As an aside, as with some of the array module functions, in some cases you can fool this with: o.someProperty = undefined; The isOwnProperty function will return false unless there is such a property defined (meaning it exists and is _not_ the undefined value) on o's prototype. I need to add this bit to the documentation. I have an idea on how the array module functions can get around this too (without using the disallowed - in - operated). You might wonder why I disallow the - in - operator in the core. It is because I want to be able to test the core (or at least the low-level bits) in _everything_ For instance, I just tested the latest build in NN4.7 (minus the Ajax and Flash modules as they have try-catch of course) this morning. You might also wonder why I would want to test _anything_ in NN4.7. It should be obvious that the less features found in a browser, the greater the likelihood that gaps in the feature detection will be exposed (and there appear to be none at this point). |