1

I've used Dean Edward's base.js. I've used it for years, but the forum is dead so I thought I'd post here and see if anyone knew what's up. The following shows my issue:

        var Animal = Base.extend({
            name: "",
            constructor: function(name){
                this.name = name
            },
            getName: function(){
                this.name
            }

        });

        var Cat = Animal.extend({

            prey: [],
            getPrey: function(){return this.prey}
        });

        var Tiger = Cat.extend({});
        var House = Cat.extend({});

        var cats = [];
        cats.push(new Tiger());
        cats.push(new House());

        cats[0].prey.push("dogs");
        cats[1].prey.push("mice");

        console.log(cats[0].getPrey());
        console.log(cats[1].getPrey());

Basically, it creates a three level hierarchy(not sure if the eldest parent is necessary) with the middle parent having an array. When two separate child instances add something to their inherited array, it appears in both children. I would think that the above code would print in the console:

["dogs"]
["mice"]

Instead, it prints:

["dogs", "mice"]
["dogs", "mice"]

Am I missing something? It's possible that this is intentional, but from a typed language OO standpoint, I'm pretty sure that's not the way things are supposed to work. If anyone has a more elegant way of doing the above, I'm all ears.

As always, much obliged.

AakashM
  • 62,551
  • 17
  • 151
  • 186
dardenfall
  • 196
  • 2
  • 9

2 Answers2

2

The fix is as follows (adding the constructor):

...snip...

var Cat = Animal.extend({

    prey: [],
     constructor: function(){
         this.prey = [];
     },
     getPrey: function(){return this.prey}
});

...snip...

The solution was given to me by a colleague that goes by the name of Miguel Bollar. He is a gentleman and a scholar.

dardenfall
  • 196
  • 2
  • 9
0

It's not a bug per se. It's not understanding the semantics. Cat.prey is a class level attribute with reference type (Object, Array in JavaScript). Unless you (re)define it in a constructor all instances will share exact same reference. It's the same as the following in Python.

class Cat:

  prey = []

  def getPrey(self):
    return self.prey

c1 = Cat()
c1.prey.append('foo')
c2 = Cat()
c2.prey.append('bar')

print c1.getPrey() # ['foo', 'bar']
print c2.getPrey() # ['foo', 'bar']

So as you've already hopefully learned, reference types should be initialized in constructor.

saaj
  • 23,253
  • 3
  • 104
  • 105
  • Well, that's different from Java which (it seems like) Dean's syntax is based on, so no, I don't think it's a semantic issue. – dardenfall Oct 18 '14 at 14:35
  • @dardenfall In Java you need to explicitly define a class-level field. I think, neither Dean based it after Java, nor should you translate Java's rigid object model to dynamic JavaScript's. The misunderstanding is of [JavaScript name resolution](http://davidshariff.com/blog/javascript-scope-chain-and-closures/), which is the semantics. I.e. your ``prey`` array is ``Cat.prototype.prey``. And of course the libraries that build feature-complete object model on top of JS' prototypes won't hide it from you. E.g. you'll have [the same thing with Qooxdoo](http://stackoverflow.com/q/14024282/2072035). – saaj Oct 20 '14 at 09:33