13 Replies - 729 Views - Last Post: 23 November 2012 - 07:12 PM

#1 AOM_Set  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 151
  • Joined: 18-December 10

JS modules/inheritance

Posted 21 November 2012 - 12:29 PM

Hi.

I am trying to work with inheritance in js. I have to make a superclass "Pet", and some sublcasses, which inherit from Pet. So far I have made a dog (which should make a "wuf" sound. Furthermore, the superclass should be made so that it can't be instanciated, so I use modules. I have written the code below so far. So when the task is done, I should be able to say something like:
var d = new Dog("dogName");
d.sound //which should say wuf
d.getName // which should return dogName (from superclass)



But when I say the above code, it says that d is undefined. I've been working for some time with this, and I'm all out of options, so help is really appreciated. Thanks

var Pet = (function(n) {     
        var name;
        this.getName = function(){   
            this.name = n || "noname";
            return this.name
        }        
	
	function dog(n){
		Pet.call(this, n);
		this.sound = "wuf";
	}

	function cat(n){
    	Pet.call(this, n);
		this.sound = "meow";
	}
	
	return{
	   Dog: dog,
	   Snake: snake
	}
	
    Dog.prototype = Pet;
    Snake.prototype = Pet;
})();





Is This A Good Question/Topic? 0
  • +

Replies To: JS modules/inheritance

#2 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 21 November 2012 - 02:19 PM

View PostAOM_Set, on 21 November 2012 - 08:29 PM, said:

But when I say the above code, it says that d is undefined.

of course, there is no function Dog() in the used scope. the only dog function is Pet.Dog().

View PostAOM_Set, on 21 November 2012 - 08:29 PM, said:

Furthermore, the superclass should be made so that it can't be instanciated,

Why? extending a "class" means an is_a relation, if the "superclass" is not instantiable, why should the extending class be? the concept of abstract classes does not work in a language that does not know classes at all.

the closest you can do is define an object as prototype (an object is not a constructor an thus cannot be instantiated) and copy it into the object’s prototype.
var pet = {
    // ...
};
function pet_name(n) 
{
    return {
        name: {
            value: n,
            writable: true,
            enumerable: true
        }
    }
}
function Dog(name)
{
    var d = Object.create(pet, pet_name(name));
    Object.defineProperty(d, "sound", {
        value: "woof"
    });
    return d;
}

var d = Dog("Waldi");
alert(d.sound);



next problem: Pet.call(this, n);, Pet is not a function, it is a plain object with two methods.

same problem: Dog.prototype = Pet;, there is no function Dog(). the only function is dog(), which is 1) in another scope and 2) has a different name (JS is case-sensitive).

you should also check some tutorials on JS inheritance, it is not as easy as your code shows (iirc, Douglas Crockford and Mozilla have some useful ones).

This post has been edited by Dormilich: 21 November 2012 - 02:34 PM
Reason for edit:: made it re-useable

Was This Post Helpful? 1
  • +
  • -

#3 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Re: JS modules/inheritance

Posted 21 November 2012 - 02:50 PM

Here's the system I use (and I just ignore the abstract class declaration problem and simply abstain from instantiating them):




This is how you create an animal class:

  function Animal(){
    this.eyes = 2;
    this.hasTail;
  }

  Animal.prototype.sleep = function(){
    alert('zzz');
  }




Then you can create a dog class which inherits from Animal:

  function Dog(){
    Animal.call()   // This is useful for instantiating w/ parameters on superclass...
  }

  Dog.prototype = new Animal();  // this is doing the inheritance




At this point, any Dog objects you create will have a sleep method, and two eyes.

  function Animal(){
    this.eyes = 2;
    this.hasTail;
  }

  Animal.prototype.sleep = function(){
    alert('zzz');
  }

  function Dog(){
    Animal.call()
    this.hasTail = true;
  }
  Dog.prototype = new Animal();
  
  d = new Dog();
  
  d.eyes;
  //-> 2



This post has been edited by NotarySojac: 21 November 2012 - 02:59 PM

Was This Post Helpful? 1
  • +
  • -

#4 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 21 November 2012 - 03:11 PM

you forgot to re-set the constructor property. and Iím not sure whether it should be Animal.call(this) (otherwise Animal() would be sufficient).
Was This Post Helpful? 0
  • +
  • -

#5 AOM_Set  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 151
  • Joined: 18-December 10

Re: JS modules/inheritance

Posted 22 November 2012 - 01:14 AM

View PostDormilich, on 21 November 2012 - 02:19 PM, said:

View PostAOM_Set, on 21 November 2012 - 08:29 PM, said:

Furthermore, the superclass should be made so that it can't be instanciated,

Why? extending a "class" means an is_a relation, if the "superclass" is not instantiable, why should the extending class be? the concept of abstract classes does not work in a language that does not know classes at all.


I'm not sure why, it is just the way the excercise was put up. My guess is that it is to force us considering using a module.

This post has been edited by AOM_Set: 22 November 2012 - 01:15 AM

Was This Post Helpful? 0
  • +
  • -

#6 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 22 November 2012 - 01:22 AM

if the task is to use the Module pattern, then inheritance is not really an option. be aware that the Module Pattern is one way of implementing a Singleton in Javascript (and before 5th Edition pretty much the only way to implement property privacy).

on the other-hand-side, inheritance is about modifying an objectís prototype, which is no concern of the Module (which returns plain objects).
Was This Post Helpful? 1
  • +
  • -

#7 AOM_Set  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 151
  • Joined: 18-December 10

Re: JS modules/inheritance

Posted 22 November 2012 - 01:32 AM

var pet = {
    // ...
};
function pet_name(n) 
{
    return {
        name: {
            value: n,
            writable: true,
            enumerable: true
        }
    }
}
function Dog(name)
{
    var d = Object.create(pet, pet_name(name));
    Object.defineProperty(d, "sound", {
        value: "woof"
    });
    return d;
}



I'm not sure that I understand your code. You don't use your pet module to anything.
var pet { //... }


I shouldn't be able to make a direct instance of the pet at all, only by saying
new ...
on the sublasses. This requires me to have every code in the module, like

var pet = {     
 //all the code in here
}


Here is the task description:

1. Create a super class Pet that has a name property.
2. Create a subclass of Pet called Dog that has a sound method that returns the string "Wuf".
3. Create another subclass of Pet called Cat that has a sound method that returns the string "Meow".
4. Test your new class hierarchy.
5. Make sure that Pet cannot be instantiated (that is, only Dog and Cat can be instantiated). [Hint: Use a module]
6. Show how to encapsulate the name property such that it can only be accessed with a getName method when the object has been constructed. You should not use ES5 (ECMAScript 5th edition) specific language features for this, only ordinary ES3.
Was This Post Helpful? 0
  • +
  • -

#8 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 22 November 2012 - 02:27 AM

problem #1: there are no classes in Javascript! you can have functions act as object constructors that loosely resemble a class, but that’s still something completely different.

1. closely related to 5., but if you use option 1), you fail the property creation. besides that if name were indeed a property of the "superclass", all Dogs and Cats would have the same name. this cannot be intended and hence the name property must be instantiated in the Dog/Cat constructor, which means that the "superclass" constructor (as constructor for an object) is superfluous. on the other-hand-side, nothing prevents you of using a function to create a set of object properties but even in classical OO languages that doesn’t qualify as superclass.

2./3. there are two different things said here
  • creating a specific constructor function
  • applying JS inheritance between "classes" (constructors)

the latter does make little sense as we know from 1. that we don’t need a "superclass". all that suffices is to use the prototype (which in itself does not necessarily mean "class" inheritance).

example, just simple prototypal inheritance. all Dog instances inherit the sound property of a "parent" object. no "superclass" (i.e. constructor) inheritance required.
you could argue that anything put in the prototype is a "superclass" but that would loosen the "class" definition so that you could call anything a class.
// the constructor
function Dog() {}
// the inheritance
Dog.prototype.sound = "woof";
// or to make it more plain
var s = {
    sound: "woof"
};
Dog.prototype = s;

// in ES5 that would be done by
var d = Object.create(s);
// without the constructor binding, though

function Cat() {}
Cat.prototype.sound = "meow";

var d = new Dog();
alert(d.sound); // woof
alert(d.hasOwnProperty("sound")); // false


4. obsolete, there is no "class hierarchy". what you can test though is, whether the prototype chain is assigned correctly (see above).

5. there are only 2 ways to accomplish that:
  • throw an Error in the constructor function Pet() (unlikely as of 1.)
  • do not use a function (and yes, the Module Pattern accomplishes that, but why not using a plain object in the first place (esp. if the privacy provided is not used))


6. all you need is a Closure

you may see that using OO terms from classical OO languages can cause more problems than it solves.

here I have used "class = constructor function" in that strict sense. the more you loosen that definition the more you can explain everything using known terms at the price of not understanding what Javascript really does.

This post has been edited by Dormilich: 22 November 2012 - 02:33 AM

Was This Post Helpful? 3
  • +
  • -

#9 AOM_Set  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 151
  • Joined: 18-December 10

Re: JS modules/inheritance

Posted 23 November 2012 - 06:16 AM

View PostDormilich, on 22 November 2012 - 02:27 AM, said:

// the constructor
function Dog() {}
// the inheritance
Dog.prototype.sound = "woof";
// or to make it more plain
var s = {
    sound: "woof"
};
Dog.prototype = s;

// in ES5 that would be done by
var d = Object.create(s);
// without the constructor binding, though

function Cat() {}
Cat.prototype.sound = "meow";

var d = new Dog();
alert(d.sound); // woof
alert(d.hasOwnProperty("sound")); // false


Thanks for the input. The above code is kind of how I made it at the begining, but got the problem of handleling the name problem.
Was This Post Helpful? 0
  • +
  • -

#10 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 23 November 2012 - 06:42 AM

yea, the assignment implies, that name is to be inherited, which is unlikely. the problem of using class-ical terms in a prototype language.
Was This Post Helpful? 0
  • +
  • -

#11 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 23 November 2012 - 10:21 AM

I might as well expand on the problem. for comparison I use PHP, which is 1) class-based and 2) also weakly typed.

PHP
class Super
{
    public $a = 1;
}
class Child extends Super
{
    public $b = 2;
}
// create 2 instances
$a = new Child();
$b = new Child();

// re-setting ->a
$a->a = 3; 

// dump
var_dump($a);
var_dump($b);

// prove that ->a is a property of Super
$o = new ReflectionObject($a);
var_dump($o->getProperty("a"));

object(Child)#1 (2) {
  ["b"]=>  int(2)
  ["a"]=>  int(3)
}
object(Child)#2 (2) {
  ["b"]=>  int(2)
  ["a"]=>  int(1)
}
object(ReflectionProperty)#4 (2) {
  ["name"]=>  string(1) "a"
  ["class"]=>  string(5) "Super"
}

now the same in JS
var Super = {
    a: 1
};
function Child()
{
    this.b = 2;
}
Child.prototype = Super;

var a = new Child();
var b = new Child();

console.log(a);
console.log(b);
console.log(a.hasOwnProperty("a"));
a.a = 3;
console.log(a);
console.log(b);
console.log(a.hasOwnProperty("a"));


Object { b=2, a=1 }
Object { b=2, a=1 }
false
Object { b=2, a=3 }
Object { b=2, a=1 }
true

as you can see, in PHP the superclass property is specific per instance (makes sense, classes are building blocks) while in JS setting the property .a causes the instance to create a new "local" property of that name and not to modify the property in the prototype chain.
Was This Post Helpful? 1
  • +
  • -

#12 AOM_Set  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 151
  • Joined: 18-December 10

Re: JS modules/inheritance

Posted 23 November 2012 - 10:43 AM

Thanks, I solved it :-)
Was This Post Helpful? 0
  • +
  • -

#13 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3541
  • View blog
  • Posts: 10,238
  • Joined: 08-June 10

Re: JS modules/inheritance

Posted 23 November 2012 - 10:59 AM

what does the solution look like?
Was This Post Helpful? 1
  • +
  • -

#14 AOM_Set  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 151
  • Joined: 18-December 10

Re: JS modules/inheritance

Posted 23 November 2012 - 07:12 PM

View PostDormilich, on 23 November 2012 - 10:59 AM, said:

what does the solution look like?

oops, I clicked vote on the above instead of quote.

The super 'class' that returns the name looks like this
var Pet = (function() {     
    function Pet(n){ 
		var name;
		this.getName = function(){
			name = n || "No name";
			return name;
		}
       } 
    ...

 }


It works fine, but I gotta call it on Pet.Dog etc.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1