0

I'm trying to get a better understanding of object oriented patterns in JavaScript. I particulary like the way EmberJS implements their classes with .extend and .create from Parent class Objects.

I've tried to implement a basic version of this on my own, but to no success, my newly instantiated Objects reference the same Object. I.e If I increment a private counter var in instance a via a public method, then separately do the same to instance b, b will reflect both increments.

I was able to achieve a de-referenced object via Object.create(myClass), however this is undesirable as I'd like to achieve this internally and also not rely on client support for that native method.

Here's a jsbin of what I've got: http://jsbin.com/zepaju/6/edit?js,console

Thanks for any help!

micahblu
  • 4,924
  • 5
  • 27
  • 33
  • 1
    An aside: It's [candidate](https://www.google.com/search?q=candidate). – Jared Farrish Jun 28 '14 at 00:44
  • Gotcha and fixed, got any ideas on the problem at hand? – micahblu Jun 28 '14 at 00:58
  • @micahblu JavaScript is [prototypical](http://stackoverflow.com/questions/2752868/does-javascript-have-classes) (prototype-based); it doesn't really have "classes," at least not in the traditional sense. – royhowie Jun 28 '14 at 01:10
  • Also, there's only one 'r' in Barack Obama's name... – bobtato Jun 28 '14 at 02:03
  • JavaScript doesn't have a private modifier and some people use closures to simulate them sacrifice the prototype. What prototype is in JavaScript and how to use it is explained here. http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Jun 28 '14 at 03:12

1 Answers1

1

This is a pretty big subject, because there isn't a perfect way to make JavaScript work like Java-- you'll always have to invent some new coding idiom, and different people have different preferences.

Looking at your linked code, it's hard to be sure what you're gunning for but it looks like the problem is that you're thinking of an object's prototype as a "class", which is copied into each "instance" (like in Java)-- this isn't the case.

Your create() function is creating each "instance" by doing Object.create(Poll), which makes a new object with the Poll object as its prototype. When you refer to properties of the resulting objects, and those properties are not directly defined on the object, what you get is a reference to a property of the single Poll object.

The fact that you've sealed the Poll object's internal variables within a closure doesn't make any difference to this; the closure variables are hidden from the outside world, but they are accessible to the methods of the Poll object, and those methods are shared between all "instances".

If you want a function that spits out objects with a particular set of methods, and which hide their internal data in a closure, that might look like:

function Poll(challenger,incumbent) {
  var challengerVotes=0;
  var incumbentVotes=0;
  return {
    voteForChallenger: function() {challengerVotes++},
    voteForIncumbent: function() {incumbentVotes++},
    winner: function() {return challengerVotes>incumbentVotes ? challenger : incumbent}
  }
}

var poll1 = Poll("Edward","Jacob");
var poll2 = Poll("Vanilla","Stilton");

poll1 and poll2 would not affect one another, and there would be no way to access the vote counts of either except through the supplied methods. I appreciate you're looking for a more generic approach but this is an example of how you might start.

bobtato
  • 1,157
  • 1
  • 9
  • 11
  • 1
    The Douglas Crockford article isn't very good, it creates an instance of Parent to set prototype of Child and doesn't re use Parent constructor by doing `Parent.apply(this,arguments)` or something similar. The exact things I've seen him complain about in "classical inheritance" but instead of blaming it on the faulty code he blames it on JavaScript. Then it modifies Function and breaks encapsulation, a strange and inconsistent thing for someone concerned with having private variables because of encapsulation. – HMR Jun 28 '14 at 07:30
  • On closer inspection, that article is not what I thought-- I read it a long time ago and it seems like I had it confused with something else. I've removed the link from the original answer as it doesn't seem that enlightening here (and is pretty turgid and out-of-date). – bobtato Jun 28 '14 at 08:31
  • What I'm aiming to understand here is how to accomplish what Ember accomplishes with its pattern for extending and creating new object / class instances via something akin to App.MyObject = Ember.Object.create(); which returns a new instance of that object, with inherited prototype chain as well any other objects that extended the original class. I'm going to go the old fashion route here and dig into their source code :) Appreciate the attempts to help – micahblu Jul 01 '14 at 17:37