QUESTION: Can a function be set up as a constant in JS?

J

JJ

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,
 
D

David Mark

JJ said:
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).
 
T

Thomas 'PointedEars' Lahn

JJ said:
// 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
 
T

Thomas 'PointedEars' Lahn

David said:
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
 
D

David Mark

Thomas said:
No doubt about that.


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
}
}

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).
 
A

Asen Bozhilov

Thomas said:
/**
 * 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;

};

But this method is useless in ECMA-262-3 environments. For backward
compatible can be good, but in inheritance pattern is not very well,
because doesn't analyse prototype chain.

function Map2(){}
Map2.prototype = new Map();
Map2.prototype.constructor = Map2;

print(Map.isInstance(new Map2())); //false

What is a benefit from that method at all? It is try to make
generalization, which isn't so precisely. I don't see reasons to test
any objects in this way in implementations, which aren't support
`instanceof` operator and `Object.prototype.isPrototypeOf (V)` method.
If i need something like this, I'll do test over interface of object.
For example if i need to call `getKey' method:

if (typeof o.getKey == 'function') {
o.getKey(key);
}

If i expect somewhere in my code `Map' instance, I'll write
documentation about this case. And of course, I'll don't do it test
above.

Regards ;~)
 
A

Andrea Giammarchi

Agreed, also instanceof simply checks the prototype and not the
constructor

If we want rely on constructors and their prototype, why create such
method rather than do this check?

if (o instanceof Map) {

}

it's even shorter than

if (Map.isInstance(o)) {

}

then, as already said

var MProto = Map.prototype;
var m = new Map;

// bye bye
Map.prototype = {};

m instanceof Map; // false
m.constructor === Map; // false

MProto.isPrototypeOf(m); // true

accordingly, believing that isInstance won't be changed, I would
rather go for something like:

Map.isInstance = (function (__proto__) {
return function (o) {
return __proto__.isPrototypeOf(o);
};
}(Map.prototype));

Regards
 
T

Thomas 'PointedEars' Lahn

Asen said:
But this method is useless in ECMA-262-3 environments. For backward
compatible can be good, but in inheritance pattern is not very well,
because doesn't analyse prototype chain.

It does not have to.
function Map2(){}
Map2.prototype = new Map();

This inheritance pattern is a problem to begin with. Often discussed,
often disapproved of.
Map2.prototype.constructor = Map2;

print(Map.isInstance(new Map2())); //false

There is no guard against stupidity.
What is a benefit from that method at all?

That a Map instance can be recognized for what it is. This is important
because there are some methods that are only available to Map instances.
RTSL.
if (typeof o.getKey == 'function') {
o.getKey(key);
}

Doesn't apply here.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Andrea said:
Agreed, also instanceof simply checks the prototype and not the
constructor

The intention here was to avoid just that.
If we want rely on constructors and their prototype, why create such
method rather than do this check?

if (o instanceof Map) {

}

it's even shorter than

if (Map.isInstance(o)) {

}

And it is less compatible.
[non sequitur]

[top post]

Learn to quote.


PointedEars
 
A

Andrea Giammarchi

And it is less compatible.

tell me which browser exactly gives you problem with instanceof ...
and if you ends up with IE4 I do believe you have no features
detections for those cases where try catch are essential ... so I hope
you don't consider your library more robust and I have already wrote
an alternative based on the true inheritance ...
 
T

Thomas 'PointedEars' Lahn

Andrea Giammarchi wrote:

[Context restored]
tell me which browser exactly gives you problem with instanceof ...

Those using implementations based on ECMAScript < 3, JavaScript < 1.5,
or JScript < 5.0. Yes, that includes IE 4.x.
and if you ends up with IE4 I do believe you have no features
detections for those cases where try catch are essential ...

try..catch can be wrapped so that a less capable compiler does not find it
(so no SyntaxError there).
so I hope you don't consider your library more robust

Yes, I do.
and I have already wrote an alternative based on the true inheritance ...

Inheritance is beside the point here, and your alternative suggestion is
not even compatible to non-Geckos. Talk about robust libraries.

BTW, trimming quotes means to leave the relevant parts.


PointedEars
 
A

Asen Bozhilov

Thomas said:
That a Map instance can be recognized for what it is.  This is important
because there are some methods that are only available to Map instances.  
RTSL.

It's a flawed argument. If you need to do it something, only with Map
instances. These methods should be with `private` signatures. There
no need dummy method like that for observing `private` properties.

"RTSL" - Don't use repeatedly abbreviations. They are with different
meaning, depend by context. And i don't need to know each abbreviation
to understand your post. In that context, "RTSL" mean "Read The
Source, Luke".
First of all, my name isn't Luke. So that abbreviation is nonsense at
all. Second, there aren't any links to your source code. Third, i was
read your code using google.

If you want better meaning of RTSL:

Rewrite The Source, Lahn.
 
A

Asen Bozhilov

Thomas said:
Andrea Giammarchi wrote:

Inheritance is beside the point here, and your alternative suggestion is
not even compatible to non-Geckos.  Talk about robust libraries.

Are you read his code? It's compatible with any ECMA-262
implementations, because `__proto__` is valid Identifier. Of course
Identifiers name like that aren't good practice. But before you blame
someone, please read precisely him code. Thanks.
 
T

Thomas 'PointedEars' Lahn

Asen said:
Are you read his code? It's compatible with any ECMA-262
implementations, because `__proto__` is valid Identifier. Of course
Identifiers name like that aren't good practice. But before you blame
someone, please read precisely him code. Thanks.

(You are still writing a lot of gibberish.)

Yes, he got me confused (intentionally?) with the __proto__ argument.
However, it is safe to say that while his code is compatible to some non-
Geckos, it is not as compatible as mine, and it certainly is not equivalent
to mine (which was the point of the exercise).

FYI, in the process I have updated the (hopefully-soon-to-be) next release
of the ECMAScript Support Matrix¹ as follows:

ECMAScript JavaScript JScript V8 JSC Opera KJS
[1] 5 [15.2.4.6] 1.5 5.5.6330 2.0 525.13 5.02 4.3.4
___
[1] Object.prototype.isPrototypeOf(Object) : boolean


PointedEars
___________
¹ <http://PointedEars.de/es-matrix>
 
T

Thomas 'PointedEars' Lahn

Thomas said:
ECMAScript JavaScript JScript V8 JSC Opera KJS
[1] 5 [15.2.4.6] 1.5 5.5.6330 2.0 525.13 5.02 4.3.4
___
[1] Object.prototype.isPrototypeOf(Object) : boolean

Should be ES 3, not 5. Further corrections are welcome (as always).


PointedEars
 
A

Asen Bozhilov

Thomas said:
(You are still writing a lot of gibberish.)

You can interpret however you want.
Yes, he got me confused (intentionally?) with the __proto__ argument.

No, there isn't world conspiracy against you.

Why do you group in table unicode escape sequences for string literals
and regular expression literals? While escape sequences in string
literals are documented in ECMA-262-1, escape sequences in regular
expression literals are part of ECMA-262 standard edition 3.
And in table there isn't unicode escape sequences as part of
IdentifierName, which ECMA-262-3 allow.
 
A

Andrea Giammarchi

Yes, he got me confused (intentionally?) with the __proto__ argument.

__proto__ property points the inherited prototype

Since what you want to do is to know if an object inherited from
Map.prototype, where in Gecko Map.prototype === new Map().__proto__, I
have used that syntax to explain the concept behind the check.

Moreover, the === operator does not tell us if the instance inherits
from extended prototype, this is why isPrototypeOf is required.

function Map() {}
function Map2() {}
Map2.prototype = new Map;

var m = new Map;
var m2 = new Map2;

m2.__proto__ === Map.prototype; // false

m.__proto__.isPrototypeOf(m2); // true

// ... and ...
m.__proto__ === Map.prototype; // true

So, how can you get confuse about that variable called __proto__?

Finally, which part of an exposed public constructor property unable
to tell you about inheritance, if any, can be considered more robust?
And why are don't you deal with IE3 as well and possibly with a
browser for Commodore 64?

Regards
 
A

Andrea Giammarchi

by the way, I have just remembered when I was playing with some T-Rex
and IE4 I wrote this library which is compatible and normalizes death
browsers:
http://devpro.it/JSL/

If interested, there are few interesting things there, have a look if
interested.

Regards
 
M

Michael Haufe (\TNO\)

by the way, I have just remembered when I was playing with some T-Rex
and IE4 I wrote this library which is compatible and normalizes death
browsers:http://devpro.it/JSL/

If interested, there are few interesting things there, have a look if
interested.

Regards

From http://devpro.it/JSL/JSLOpenSource.js
---------
if(typeof(XMLHttpRequest)==="undefined"){XMLHttpRequest=function(){
var tmp=null,elm=navigator.userAgent;
if(elm.toUpperCase().indexOf("MSIE 4")<0&&window.ActiveXObject)
tmp=elm.indexOf("MSIE 5")<0?new ActiveXObject("Msxml2.XMLHTTP"):new
ActiveXObject("Microsoft.XMLHTTP");
return tmp;
}};
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top