Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #30232

Re: Comparing some of the ways to create objects

From Scott Sauyet <scott@sauyet.com>
Newsgroups comp.lang.javascript
Subject Re: Comparing some of the ways to create objects
Date 2016-04-06 23:42 +0000
Organization A noiseless patient Spider
Message-ID <ne46s8$8td$1@dont-email.me> (permalink)
References <hbc2gbpvk5nk24b0qupps6cjqn8fm3ar5e@4ax.com> <ndspod$lhh$1@dont-email.me> <0ebagb5j5s77hr64fhi3vlpr64asu3gous@4ax.com>

Show all headers | View raw


John Harris wrote:
> Scott Sauyet wrote:
> 
>   <snip>
>> My techniques follow.  I'm wondering if you see these ones as somehow
>> lesser techniques than the three you present.  And if so, why is that?
> 
> In general, any technique for the creation of one object can be wrapped
> in a function and used in several places and reused in other projects.
> The question is : does the function provided something extra that
> constructors can't provide *and* is this needed here? If not then an
> ordinary constructor is likely to be simpler and easier to read, and
> sometimes faster.

Of course, but in Javascript, there are a large number of such techniques,
and they each offer different advantages and disadvantages.  As you noted,
#4 and #5 below each offer private properties.  They also offer read-only
properties (not getters, BTW.)  In addition, #5 can be used directly 
anywhere a plain function is required without the overhead of adding 
`new`, for instance as a callback to `Array.prototype.map`.  #6 builds 
the same sort of object prototype structure as your examples with 
significantly less cognitive overhead.

I'm not trying to suggest that any of these are the definitive way to 
handle OOP in Javascript.  I don't think there is such a thing.  But 
these do offer useful features that differ from the features provided by 
the techniques you provided.  There are still others we could discuss.

That's what I was trying to get at.  Do you think that there is something 
special about your original list, or was it simply the first techniques 
that came to mind?

>>=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>> 
>>   function Thing4(phrase) {
>>      var count = 0;
>>      this.toString = function() {return phrase;}
>>      this.incr = function() {count++;} Object.defineProperties(this,
>>      {text: {
>>        get: function() {return phrase;}
>>      }, count: {
>>        get: function() {return count;}
>>      }})
>>    } // Thing4
>>
>>    var a4 = new Thing4("Hello from Thing4 a4");
>>    [ ... ]
> 
> This makes count and phrase private variables and defines getters for
> them. I'm not a fan of private variables, getters, and setters unless
> they are really really needed. If your programmers include someone who
> can't stop corrupting objects while the program is running then get rid
> of them. On the other hand, in a library if someone corrupts your object
> then it's your fault : the customer is always right, i.e shouts louder
> :-(

Are you suggesting that your distaste for these constructs should dictate 
how others write their code?  If you release version 1 of your API and 
some consumer of it starts to depend on what you thought was your 
internals, you might start to enjoy to power of encapsulation when you 
try to write version 2 and find that you can't modify those things you 
always planned to clean up.  If nothing else, encapsulation is generally 
seen as one of the main tenets of OOP.

By the way, this does not define getter-functions.  It only makes the 
properties `text` and `count` read-only.  I tried to write each version 
in a way that might change the construction mechanism but otherwise kept 
the public API of your original examples.  That included the behavior of 
the `incr` and `toString` methods and the existence of a readable `count` 
property.  (Looking back, I realize that the `text` property was not 
necessary here.)  Beyond that, I felt free to do as I chose, and here, I 
chose not to allow a consumer to modify `count`.  It seems likely that 
the existence of a method like `incr` implies some invariant that would 
be broken by a publicly mutable `count` property.


>>    function thing5(phrase) {
>>      var count = 0;
>>      return {
>>        toString: function() {return phrase;},
>>        incr: function() {count++},
>>        get count() {return count;}
>>      };
>>    } // thing5
>>
>>    var a5 = thing5("Hello from thing5 a5");
>>    [ ... ]

But, while this might not be suitable for millions of instances due to 
the increased memory footprint, it also has the advantage of being easier 
to use in higher-order abstractions:

    ["Phrase 1", "Phrase 2", "Prase 3"].map(thing5);

This is significantly more ergonomic than

    ["Phrase 1", "Phrase 2", "Prase 3"].map(function(phrase) {
      return new Thing1(phrase);
    });

And of course it shares the advantages of Thing4 in terms of greater 
encapsulation.

>>    var Thing6 = {
>>      init: function(phrase) {
>>        this.text = phrase;
>>        this.count = 0;
>>      },
>>      incr: function() {
>>        this.count++;
>>      },
>>      toString: function() {
>>        return this.text ;
>>      }
>>    }; // Thing6
>>
>>    var a6 = Object.create(Thing6);
>>    a6.init("Hello from Thing6 a6");
>>    [ ... ]
> 
> I C++ circles, i.e in comp.lang.c++.moderated, an initialise function
> provokes cries of Eugh! It's annoying to have to write two things. More
> important, it's too easy to forget the init or to miss it out when
> copying and pasting elsewhere.
> 
> Really, all this example does is to implement a constructor function.
> Why bother? [ ... ]

The C++ world has a clear-cut way to do this.  In some ways C++ is to 
Javascript like Python is to Perl.  In Javascript, there simply is no 
clear-cut definitive way to do these things, so we get to frequently 
discuss varying approaches.

One advantage of this is well described in an article by Kyle Simpson 
[1].  The point is that all Javascript's inheritance mechanism is meant 
to do is to set up a delegation mechanism between simple objects.  The 
constructor function grafts an unfortunately messy layers onto this for 
little benefit, and changes a very simple conceptual model [2] into an 
extremely convoluted one [3].

I agree with Kyle Simpson in many ways.  I think he (and Eric Elliott, 
who is the loudest proponent of this point of view) oversell the style of 
Thing6 as the only reasonable way to do OOP in Javascript.  But it is 
certainly *one* reasonable way.

Still, my big question is whether you find these techniques somehow 
inferior to your original list.  Do you believe your list captures the 
essence of the set of reasonable object creation techniques in Javascript?


  [1]: <https://davidwalsh.name/javascript-objects-deconstruction>
  [2]: <https://davidwalsh.name/demo/JavaScriptObjects--OnlyObjects.png>
  [3]: <https://davidwalsh.name/demo/JavaScriptObjects--Full.png>

  -- Scott

Back to comp.lang.javascript | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-03 16:09 +0100
  Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-04 04:15 +0000
    Re: Comparing some of the ways to create objects Stefan Weiss <krewecherl@gmail.com> - 2016-04-04 15:20 +0200
      Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-05 04:04 +0000
    Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-04 16:48 +0100
      Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-05 04:04 +0000
        Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-07 15:07 +0100
          Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-08 01:10 +0000
            Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-08 14:55 +0100
    Re: Comparing some of the ways to create objects Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2016-04-04 22:12 +0200
      Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-05 09:57 +0100
    Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-06 16:41 +0100
      Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-06 23:42 +0000
        Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-07 16:09 +0100
          Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-08 02:05 +0000
            Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-08 15:43 +0100
              Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-09 00:01 +0000
                Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-09 16:46 +0000
                Re: Comparing some of the ways to create objects Scott Sauyet <scott@sauyet.com> - 2016-04-10 16:51 +0000
                Re: Comparing some of the ways to create objects Stanimir Stamenkov <s7an10@netscape.net> - 2016-05-08 17:27 +0300
                Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-10 11:31 +0100
                Re: Comparing some of the ways to create objects John Harris <niam@jghnorth.org.uk.invalid> - 2016-04-10 11:52 +0100

csiph-web