"static" constructor functions?

Discussion in 'Javascript' started by nick, Jan 24, 2010.

  1. nick

    nick Guest

    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] = 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] = 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
    nick, Jan 24, 2010
    #1
    1. Advertising

  2. 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] = 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] = 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] = 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/
    Garrett Smith, Jan 24, 2010
    #2
    1. Advertising

  3. nick

    nick Guest

    On Jan 24, 3:11 am, Garrett Smith <> 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
    nick, Jan 24, 2010
    #3
  4. 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
    John G Harris, Jan 24, 2010
    #4
  5. nick wrote:

    >   function List()
    >   {
    >     for (var i=arguments.length; i--; )
    >       this[arguments] = 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] = true;
    }
    return o;
    }
    Asen Bozhilov, Jan 24, 2010
    #5
  6. nick

    nick Guest

    On Jan 24, 10:20 am, Asen Bozhilov <> 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. :)
    nick, Jan 24, 2010
    #6
  7. 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] = 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] = true;
    }
    }
    List.prototype.get = function(){};
    List.prototype.forEach = function(){};


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

    Regards ;)
    Asen Bozhilov, Jan 24, 2010
    #7
  8. nick

    RobG Guest

    On Jan 25, 4:47 am, nick <> wrote:
    > On Jan 24, 10:20 am, Asen Bozhilov <> 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
    RobG, Jan 25, 2010
    #8
  9. nick wrote:
    > On Jan 24, 3:11 am, Garrett Smith <> 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/
    Garrett Smith, Jan 25, 2010
    #9
  10. 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$> (2004)
    Thomas 'PointedEars' Lahn, Jan 25, 2010
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Victor Bazarov

    static and non-static functions

    Victor Bazarov, Apr 2, 2005, in forum: C++
    Replies:
    4
    Views:
    7,170
    Stephen Howe
    Apr 2, 2005
  2. tropos
    Replies:
    3
    Views:
    453
  3. Replies:
    9
    Views:
    948
    Ben Bacarisse
    Feb 6, 2006
  4. Replies:
    4
    Views:
    4,121
    Alf P. Steinbach
    Mar 3, 2006
  5. Generic Usenet Account
    Replies:
    10
    Views:
    2,222
Loading...

Share This Page