Problem statement
You need to create the
Animal
base class having four fields:a.
name
b.
sound
c.
owner
d.
favFood
You need to create a derived class
Cat
such that every instance ofCat
inherits instance members ofAnimal
. In addition,Cat
adds a new instance membermode
.
Animal
andCat
class should enforce encapsulation amidst construction and modification of objects.
Solution
<!DOCTYPE html>
<html>
<head>
<title> OOP assignment</title>
<meta charset="UTF-8">
</head>
<body>
<script language="javascript" type="text/javascript">
function Animal() {
this.name = "No Name";
this.sound = "Grrr";
this.owner = "Homeless";
this.favFood = "Anything";
/* Animal.__proto__ points to Function.prototype */
}
/* Animal.prototype.__proto__ points to Object.prototype */
Animal.prototype.setOwner = function(newOwner){
if (typeof newOwner != 'undefined'){
this.owner = newOwner;
}
else
{
document.write("Please enter a valid owner name" + "<br>");
}
}
Animal.prototype.getOwner = function(){
return this.owner;
}
Animal.prototype.setName = function(newName){
if (typeof newName != 'undefined'){
this.name = newName;
}
else{
document.write("Please enter a valid animal name" + "<br>");
}
}
Animal.prototype.getName = function(){
return this.name;
}
Animal.prototype.setNoise = function(newNoise){
if (typeof newNoise != 'undefined'){
this.sound = newNoise;
}
else{
document.write("Please enter a valid animal sound" + "<br>");
}
}
Animal.prototype.getNoise = function(){
return this.sound;
}
/* dog.__proto__ points to Animal.prototype */
var dog = new Animal();
document.write(dog.getName() + "<br />");
dog.setName("Spot");
dog.setOwner("Paul");
dog.setNoise();
document.write(dog.getName() + "<br />");
document.write(dog.getOwner() + "<br />");
document.write(dog.getNoise() + "<br />");
/* Cat.__proto__ points to Function.prototype */
function Cat() {
/*
Below line will add members name/sound/owner/favFood to an instance of Cat(),
with default values
*/
Animal.call(this);
/* another member of Cat instance*/
this.mode = "Happy";
}
/*
Aftre executing, below line of code,
Cat.prototype.__proto__ will point to Animal.prototype;
*/
Cat.prototype = Object.create(Animal.prototype);
/*
In the above line, when Cat.prototype.__proto__ points to Animal.prototype,
Cat.prototype.constructor automatically points to Animal, so this below line
*/
Cat.prototype.constructor = Cat;
Cat.prototype.getMode = function(){
return this.mode;
}
Cat.prototype.setMode = function(newMode){
if (typeof newMode != 'undefined'){
this.mode = newMode;
}
else{
document.write("Please enter a valid animal mode" + "<br>");
}
}
/* sophie.__proto__ points to Cat.prototype */
var sophie = new Cat();
sophie.setName("Sophie");
sophie.setOwner("Derek");
sophie.setNoise("Meow");
document.write(sophie.getName() + "<br />");
document.write(sophie.getOwner() + "<br />");
document.write(sophie.getNoise() + "<br />");
</script>
<noscript>
<h3>This site requires Javascript</h3>
</noscript>
</body>
</html>
Output
output
Does the
__proto__
hierarchy and contents ofCat.prototype
look good?Do the
Animal
andCat
class enforce encapsulation amidst construction and modification of objects??What is the problem, when I say,
Cat.prototype = new Animal()
instead ofCat.prototype = Object.create(Animal.prototype);
?
-
\$\begingroup\$ Follow-up question \$\endgroup\$200_success– 200_success2015年12月28日 06:56:23 +00:00Commented Dec 28, 2015 at 6:56
1 Answer 1
Does the
__proto__
hierarchy and contents of Cat.prototype looks good?
It looks reasonable. You can test via sophie instanceof Animal
or Object.getPrototypeOf(sophie)
depending on need.
Did Animal and Cat class enforce encapsulation?
No. We can still do sophie.name='foo'
via the objects fields. For instance i could set sophie.name = function() { alert('hello, world'); };
Encapsulation would look more like below whereby we control how and what happens to the values of those fields:
function Animal(name, sound, owner, favFood) {
var _name = name || "animal";
var _sound = sound || "roar";
var _owner = owner || "Homeless";
var _favFood = favFood || "Jelly beans";
Object.defineProperties(this, {
'name': {
get: function () {
return _name;
},
set: function (name) {
_name = name;
}
},
'owner': {
get: function () {
return _owner;
},
set: function (ownerName) {
_owner = ownerName;
}
}
});
}
There are additional configuration options like leaving off a setter for read-only access, plus writable, configurable and enumerable parameters which can help you completely lock the object down.
What is the problem, when I say,
Cat.prototype = new Animal()
instead ofCat.prototype = Object.create(Animal.prototype);
?
Cat.prototype = new Animal()
invokes the function and therefore executes all its statements so it potentially has more/unintended side effects.
-
\$\begingroup\$ Get and set should be in Animal.prototype \$\endgroup\$overexchange– overexchange2015年12月17日 12:49:01 +00:00Commented Dec 17, 2015 at 12:49
-
\$\begingroup\$ It depends upon your requirements. If you do that then you'll need a closure pattern to be able to access
var _name
etc. Don't make the mistake of just blindly attaching properties and methods to the prototype because "that's how it should be done". It's a horses for courses thing. If you only need a bunch of Animals and your primary concern is privacy and encapsulation then the above is fine. It's easy to read, understand and maintain. If however you're spinning up 1000s of Animals or have other requirements then yes you will benefit from looking at alternatives. \$\endgroup\$rism– rism2015年12月17日 20:53:27 +00:00Commented Dec 17, 2015 at 20:53
Explore related questions
See similar questions with these tags.