Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Javascript > "static" constructor functions?

Reply
Thread Tools

"static" constructor functions?

 
 
nick
Guest
Posts: n/a
 
      01-24-2010
So, I was making a simple constructor function for a List pseudoclass
(correct terminology?), and it looked like this:
....

function List()
{
for (var i=arguments.length; i--; )
this[arguments[i]] = true;
}

....
This is kind of useful; now I can can create simple lists and use
for...in to iterate over them, where the variable on the left hand
side of 'in' is the value I actually want, not an index to the value I
want. But now I thought, what if someone does not know that they need
to use 'new' when calling a function-as-constructor, and they try
something like this?

var trees = List('maple', 'oak', 'palm');

In this case 'this' would reference the parent object of the function,
not the new List object being constructed. The variable 'trees' would
not contain a list, and the parent object would have all kinds of tree
names as properties now. Not good. So I thought this might be safer:
....

// constructor for simple list
function List()
{
if (className(this)!='List')
return List.apply(new List(), arguments);
for (var i=arguments.length; i--; )
this[arguments[i]] = true;
return this;
}

// class name
function className (o)
{
var noname = '(undefined)';
if (o===null || o===undefined || !o.constructor)
return noname;
var c = String(o.constructor);
var n = /function\s+(\w+)\b/.exec(c);
return n && n[1] ? n[1] : noname;
}

....
This seems to work great, and now lists can be created by using 'new
List(...)' or just 'List(...)', interchangeably. To me, this seems
like a more foolproof solution with less potential for accidental
misuse. The question is, am I going about it the right way? Extracting
the class name from the constructor seems a little hackish. Is there a
better way to tell what "class" an object is, or some way to determine
whether a function was called with the 'new' keyword or not? TIA for
any advice.

-- Nick
 
Reply With Quote
 
 
 
 
Garrett Smith
Guest
Posts: n/a
 
      01-24-2010
nick wrote:
> So, I was making a simple constructor function for a List pseudoclass
> (correct terminology?), and it looked like this:
> ...
>
> function List()
> {
> for (var i=arguments.length; i--; )
> this[arguments[i]] = true;
> }
>


If you use an array for a parameter, it makes it easier for
implementations to optimize the call.

function List(array) {
for (var i=0; i < array.length; i++) {
this[array[i]] = true;
}
}

> ...
> This is kind of useful; now I can can create simple lists and use
> for...in to iterate over them, where the variable on the left hand
> side of 'in' is the value I actually want, not an index to the value I
> want. But now I thought, what if someone does not know that they need
> to use 'new' when calling a function-as-constructor, and they try
> something like this?
>
> var trees = List('maple', 'oak', 'palm');
>


That would create three properties of the global object all having value
`true`, leaving `trees` with value `undefined`.

> In this case 'this' would reference the parent object of the function,
> not the new List object being constructed. The variable 'trees' would
> not contain a list, and the parent object would have all kinds of tree
> names as properties now. Not good. So I thought this might be safer:
> ...

The properties would be of the `global` object. I don't know what you
mean by "parent" object.

>
> // constructor for simple list
> function List()
> {
> if (className(this)!='List')
> return List.apply(new List(), arguments);
> for (var i=arguments.length; i--; )
> this[arguments[i]] = true;
> return this;
> }
>
> // class name
> function className (o)
> {
> var noname = '(undefined)';
> if (o===null || o===undefined || !o.constructor)
> return noname;
> var c = String(o.constructor);
> var n = /function\s+(\w+)\b/.exec(c);
> return n && n[1] ? n[1] : noname;
> }
>
> ...
> This seems to work great, and now lists can be created by using 'new
> List(...)' or just 'List(...)', interchangeably. To me, this seems
> like a more foolproof solution with less potential for accidental
> misuse. The question is, am I going about it the right way? Extracting
> the class name from the constructor seems a little hackish. Is there a
> better way to tell what "class" an object is, or some way to determine
> whether a function was called with the 'new' keyword or not? TIA for
> any advice.
>

There are other ways to go about doing that. You could use `this
instanceof List`, to start with.

The errors are easy enough to avoid and should be immediately obvious.
Just use `new`.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
 
Reply With Quote
 
 
 
 
nick
Guest
Posts: n/a
 
      01-24-2010
On Jan 24, 3:11*am, Garrett Smith <(E-Mail Removed)> wrote:
>
> If you use an array for a parameter, it makes it easier for
> implementations to optimize the call.


Thanks for pointing that out. I'm really thinking more about concise
syntax here than optimization... I'm pretty sure calling List without
'new' in the second example will result in a total of 3 calls to List
-- the initial call, a constructor call with 'new' and another call
using 'apply'. So optimization is pretty much out the window here
anyway, although I suppose I should optionally allow an array as the
first parameter.

> > In this case 'this' would reference the parent object of the function,
> > not the new List object being constructed. ...

>
> The properties would be of the `global` object. I don't know what you
> mean by "parent" object.
>


Oops, I did say "in this case" didn't I? I was assuming the List
constructor would be in some library, so it would be a property of
some other object than the global object... that's all I meant by the
'parent' object.

> There are other ways to go about doing that. You could use `this
> instanceof List`, to start with.


Ah, instanceof is perfect, thank you!

> The errors are easy enough to avoid and should be immediately obvious.
> Just use `new`.


That's certainly true, I'm using 'new' with my lists anyway. I wanted
a way to be sure a constructor was being called with new, and I
figured instead of throwing an error I'd just have it call itself with
new if it was not being called with new, since that would be the only
possible legitimate intended use of that syntax. Thanks for pointing
me towards instanceof, it does exactly what I need.

-- Nick
 
Reply With Quote
 
John G Harris
Guest
Posts: n/a
 
      01-24-2010
On Sat, 23 Jan 2010 at 23:27:31, in comp.lang.javascript, nick wrote:

<snip>

>a List pseudoclass
>(correct terminology?),

<snip>

Whatever you call it someone will complain. If you want to be posh and
mathematically correct you could call it a class of List objects.

John
--
John Harris
 
Reply With Quote
 
Asen Bozhilov
Guest
Posts: n/a
 
      01-24-2010
nick wrote:

> * function List()
> * {
> * * for (var i=arguments.length; i--; )
> * * * this[arguments[i]] = true;
> * }
>


What is the benefit from using native object created from List
[[Construct]] method?

function list()
{
var o = {};
for (var i = arguments.length; i--
{
o[arguments[i]] = true;
}
return o;
}



 
Reply With Quote
 
nick
Guest
Posts: n/a
 
      01-24-2010
On Jan 24, 10:20*am, Asen Bozhilov <(E-Mail Removed)> wrote:
>
> What is the benefit from using native object created from List
> [[Construct]] method?


Nothing, really. I guess there's no way I can add any methods to List
(or function properties to List's prototype, you know what I mean)
without breaking for/in, so it probably shouldn't be a class anyway.
Still, I learned something useful.
 
Reply With Quote
 
Asen Bozhilov
Guest
Posts: n/a
 
      01-24-2010
nick wrote:

> Nothing, really. I guess there's no way I can add any methods to List
> (or function properties to List's prototype, you know what I mean)
> without breaking for/in, so it probably shouldn't be a class anyway.
> Still, I learned something useful.


At all this design for my is broken, because you mix your own
properties and allow user to inject properties in your own object. See
below:

function List()
{
for (var i = arguments.length; i--
{
this[arguments[i]] = true;
}
}
List.prototype.get = function(){};
List.prototype.forEach = function(){};


var o = new List('prop1', 'prop2', 'prop3');
o.get(); //fine
o.forEach(); //fine

var o1 = new List('get', 'forEach');
try {
o1.get();
}catch(e) {
window.alert(e instanceof TypeError); //true
}

try {
o1.forEach();
}catch(e) {
window.alert(e instanceof TypeError); //true
}

So user of your constructor, can shadow properties in Prototype chain,
and that can be harmful and dangerous. You can use different
approach.

function List()
{
this._list = {};
for (var i = arguments.length; i--
{
this._list[arguments[i]] = true;
}
}
List.prototype.get = function(){};
List.prototype.forEach = function(){};


var o = new List('get', 'forEach', 'test');
o.get();
o.forEach();

Regards
 
Reply With Quote
 
RobG
Guest
Posts: n/a
 
      01-25-2010
On Jan 25, 4:47*am, nick <(E-Mail Removed)> wrote:
> On Jan 24, 10:20*am, Asen Bozhilov <(E-Mail Removed)> wrote:
>
>
>
> > What is the benefit from using native object created from List
> > [[Construct]] method?

>
> Nothing, really. I guess there's no way I can add any methods to List
> (or function properties to List's prototype, you know what I mean)
> without breaking for/in,


Simple for..in is made more difficult but it's not fundamentally
broken. A bigger issue is items in your list shaddowing methods on the
prototype chain. If your List object has a sort method on it's
prototype, what happens when you create a list that has a member
'sort'?


> so it probably shouldn't be a class anyway.


It can be implemented a number of ways, a "class" is just one. A list
instance could be an object with a list property that is an array that
is the list. That way, members of the list don't get in the way of the
object's properties and methods.

But then you might as well just use an array and have "list" functions
that operate on it.


--
Rob
 
Reply With Quote
 
Garrett Smith
Guest
Posts: n/a
 
      01-25-2010
nick wrote:
> On Jan 24, 3:11 am, Garrett Smith <(E-Mail Removed)> wrote:
>> If you use an array for a parameter, it makes it easier for
>> implementations to optimize the call.

>
> Thanks for pointing that out. I'm really thinking more about concise
> syntax here than optimization... I'm pretty sure calling List without
> 'new' in the second example will result in a total of 3 calls to List
> -- the initial call, a constructor call with 'new' and another call
> using 'apply'. So optimization is pretty much out the window here
> anyway, although I suppose I should optionally allow an array as the
> first parameter.
>
>>> In this case 'this' would reference the parent object of the function,
>>> not the new List object being constructed. ...

>> The properties would be of the `global` object. I don't know what you
>> mean by "parent" object.
>>

>
> Oops, I did say "in this case" didn't I? I was assuming the List
> constructor would be in some library, so it would be a property of
> some other object than the global object... that's all I meant by the
> 'parent' object.
>

I think by "parent" you mean the Base object.

If a function is called with no Base or with activation object as base,
then base is null. When Base is null, in ES3, the global object is used
as the `this` value for the call.

In ES5 strict mode, the `this` value is not coerced to an object; the
global object is not used implicitly. From the specification:

| If this is evaluated within strict mode code, then the this value is
| not coerced to an object. A this value of null or undefined is not
| converted to the global object and primitive values are not converted
| to wrapper objects. The this value passed via a function call
| (including calls made using Function.prototype.apply and
| Function.prototype.call) do not coerce the passed this value to an
| object (10.4.3, 11.1.1, 15.3.4.3, 15.3.4.4).

var isPrimitiveThis = (function(a){"use strict";
return a === this;
})();

In ES5 implementation, this should return true.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
 
Reply With Quote
 
Thomas 'PointedEars' Lahn
Guest
Posts: n/a
 
      01-25-2010
Garrett Smith wrote:

> nick wrote:
>> Oops, I did say "in this case" didn't I? I was assuming the List
>> constructor would be in some library, so it would be a property of
>> some other object than the global object... that's all I meant by the
>> 'parent' object.

>
> I think by "parent" you mean the Base object.


Which is not a proper name as well, thus must be written either lowercase or
with leading uppercase in all words, to avoid the ambiguity that `Base'
would be the proper name. Cf. "host object", which you also write wrong
despite being told several times.


PointedEars
--
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
-- Richard Cornford, cljs, <cife6q$253$1$(E-Mail Removed)> (2004)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
A constructor calling another constructor (default constructor)? Generic Usenet Account C++ 10 11-28-2007 04:12 AM
Copy constructor hides default constructor Aire C++ 3 01-25-2004 05:47 PM
java like constructor calling constructor lallous C++ 5 01-23-2004 11:52 PM
calling a constructor within a constructor Brett Irving C++ 3 06-29-2003 10:43 AM
why it's not possible calling constructor from constructor? Giulio C++ 9 06-25-2003 03:56 PM



Advertisments