Actual code.
function Animal(name) {
this.name = name;
}
function Rabbit(speed) {
Animal.call(this, 'Rabbit');
this.speed = speed;
}
Rabbit.prototype = Animal;
var rabbit = new Rabbit(50);
console.log(rabbit.name, rabbit.speed);
I expected to have console output:
Rabbit 50
But I have
Animal 50
Can anybody explain why Animal function doesn't rewrite its name property?
Animal just a function
'function' object has a property 'name'
for example
function app(){
console.log("hello")
}
console.log(app.name) // "app"
function Animal(name){
this.name = name;
}
console.log(Animal.name) // "Animal"
so Animal object has a property 'name', function object also has a property 'name'
you can try this
function Animal(name) {
this.notname = name; //do not use "name" as a property name
}
function Rabbit(speed) {
Animal.call(this, 'Rabbit');
this.speed = speed;
}
Rabbit.prototype = Animal;
var rabbit = new Rabbit(50);
console.log(rabbit.notname, rabbit.speed);
or
function Animal(name) {
this.name = name;
}
function Rabbit(speed) {
Animal.call(this, 'Rabbit');
this.speed = speed;
}
Rabbit.prototype = new Animal();
//you should point the Rabbit.prototype to a Animal object,not a function
var rabbit = new Rabbit(50);
console.log(rabbit.name, rabbit.speed);
Using Object.create, you should end up with something like:
function Animal(name) {
this.name = name
}
function Rabbit(speed) {
Animal.call(this, 'Rabbit')
this.speed = speed
}
Rabbit.prototype = Object.create(Animal.prototype)
// If you don't set this line, `new Rabbit` would call `Animal` constructor
Rabbit.prototype.constructor = Rabbit
var rabbit = new Rabbit(50)
console.log(rabbit.name, rabbit.speed)
Related
Prior to using ES6 we could instantiate a "class" like so...
var Animal = function(){}
and then...
var dog = new Animal()
the context within the "class" will be the class (instance) itself
var Animal = function( name ){
this.name = name;
this.getName = function(){
// the context here (this) is the class (Animal)
return this.name; // works well
}
}
The question is, if I wouldn't want to pollute the root scope and use sub-objects, for various uses, then the context would become the object in which the function is being kept
var Animal = function( name ){
this.utilities = {
this.getName : function(){
// the context here is the 'utilities' object so...
return this.name // wouldn't work
}
}
}
of course we could always use something in the form of
dog.utilities.getName.call(dog)
but this would be kind of long and uncomfortable...
is there a way to create the 'utilities' object and apply the context to all of its functions to point back to the root scope? without having to use call and apply every time? (an answer without using ES6 would be great...)
One way to ensure that this is what you want it to be in the various utilities functions is to use arrow functions for them, since arrow functions close over the this where they're defined:
class Animal {
constructor(name) {
this.name = name;
this.utilities = {
getName: () => { // This is an arrow function
return this.name; //
} //
};
}
}
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
This is basically the ES2015+ version of the old var t = this; solution:
function Animal(name) {
var t = this;
this.name = name;
this.utilities = {
getName() {
return t.name;
}
};
}
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
In both cases, this means that you're creating new function objects for each individual instance of Animal (the code will be shared between those objects, but the objects are distinct). That's fine unless there are going to be a lot of Animal instances.
Alternately, you could have a helper that you pass the instance to:
const Animal = (function() {
class Utilities {
constructor(animal) {
this.a = animal;
}
getName() {
return this.a.name;
}
}
class Animal {
constructor(name) {
this.name = name;
this.utilities = new Utilities(this);
}
}
return Animal;
})();
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
or
var Animal = (function() {
function Utilities(animal) {
this.a = animal;
}
Utilities.prototype.getName = function getName() {
return this.a.name;
};
return function Animal(name) {
this.name = name;
this.utilities = new Utilities(this);
}
})();
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
...which lets utilities reuse its function objects via Utilities.prototype.
You could probably use the following:
var utilities = function (context) {
return {
getName: function () {
console.log(context.name)
}
}
}
var Animal = function( name ){
this.name = name
this.utilities = utilities.call(null, this)
}
var dog = new Animal('dog')
dog.utilities.getName()
But, if you are okay doing this: dog.getName() instead of dog.utilities.getName() then you might have a cleaner solution (IMO) as follows:
var Animal = function( name ){
this.name = name
}
var utilities = {
getName: function () {
console.log(this.name)
}
};
Object.assign(Animal.prototype, utilities)
var dog = new Animal('dog')
dog.getName()
Let me know if that works. Thanks.
NEW ANSWER:
var UTILITIES = {
getName: function () {
console.log(this.self.name)
}
}
var Animal = function (name) {
this.name = name
this.utilities = Object.create(UTILITIES, {
self: {
value: this
}
})
}
var dog = new Animal('dog')
dog.utilities.getName()
Variation includes the use of a 'self' attribute which points to the instance of interest. Now, this could look more intuitive.
You can use getter methods. I find them very useful for cases where I need formatted value. This way, the utilities/ logic is only known to this class and is not exposed outside.
function Person(fname, lname) {
var _fname = fname;
var _lname = lname;
Object.defineProperty(this, 'fullName', {
get: function(){
return _fname + ' ' + _lname
}
});
Object.defineProperty(this, 'firstName', {
get: function(){
return _fname
},
set: function(value) {
_fname = value;
}
});
Object.defineProperty(this, 'lastName', {
get: function(){
return _lname
},
set: function(value) {
_lname = value;
}
});
}
var person = new Person('hello', 'world');
console.log(person.fullName);
person.firstName = 'Hello';
console.log(person.fullName);
person.lastName = 'World'
console.log(person.fullName);
Getting undefined value while inheritance in JavaScript OOPS. Student object doesn't inheritance the Person Object
function person(name, age) {
this.name = name;
this.age = age;
this.say = function() {
return this.name + " says Hi..";
}
}
var p1 = new person("Mahesh", "33");
var p2 = new person("Girish", "30");
console.log(p1.say());
console.log(p2.say());
// Inheritance
function student() {};
student.prototype = new person();
var stud1 = new student("Nakktu", "32");
console.log(stud1.say());
You still have to call your super class from within the constructor of the sub class. See this MDN link for more information.
function person(name, age) {
// When no name is provided, throw an error.
if (name === undefined) {
throw 'Unable to create instance of person. Name is required.';
}
this.name = name;
this.age = age;
this.say = function() {
return this.name + " says Hi..";
}
}
var p1 = new person("Mahesh", "33");
var p2 = new person("Girish", "30");
console.log(p1.say());
console.log(p2.say());
// Inheritance
function student(name, age) {
// You need to call your super class.
person.call(this, name, age);
};
// Don't use "new person()", your code will stop working when person() throws
// an error when the 'name' param is required and missing.
student.prototype = Object.create(person.prototype);
var stud1 = new student("Nakktu", "32");
console.log(stud1.say());
Have trouble with object creation. Console says that something wrong in the last line. Please tell how it should be, I more familar with Java, so this is little bit confusing for me.
var dog = {
name:"Dog",
age:"11",
getName : function() {
alert(this.name);
}
}
function Dog(name, age) {
this.name = name;
this.age = age;
}
var d1 = new Dog("Rex", 8);
d1.getName();
Your dog is just a simple Object literal,
that means that your getName is bound to it, not to your Dog class.
You can make that function a method of Dog instead:
/*var dog = {
name:"Dog",
age:"11",
getName : function() {
alert(this.name);
}
}*/
function Dog(name, age) {
this.name = name;
this.age = age;
}
Dog.prototype.getName = function() {
console.log( this.name );
}
var d1 = new Dog("Rex", 8);
d1.getName(); // "Rex"
Here's a variant that uses your settings "defaults"
function Dog() {
this.name = "Dog"; // Default name
this.age = 11; // Default age
}
Dog.prototype.getName = function() {
console.log( this.name );
}
var d1 = new Dog();
d1.name = "Rex"; // Override default name
d1.getName(); // "Rex"
You can use class with syntaxic sugar to properly create objects in ES6.
In your exemple that would write like this :
'use strict';
class Dog{
constructor(name, age){
this.name = name;
this.age = age;
}
getName(){
console.log(this.name);
}
}
let doggy = new Dog("krypto", 125);
doggy.getName();
Traditional OO in JavaScript
function Dog(name, age) {
this.name = name || "Dog";// if the name is not given, it defaults to "Dog"
this.age = age || "11";
}
Dog.prototype.getName = function() {
alert(this.name);
}
var d1 = new Dog("Rex", 8);
d1.getName();
More Explicit OO in JavaScript
function createDog(name, age) {
// create a new dog and return it
var dog = {
name: name || "Dog",// if the name is not given, it defaults to "Dog"
age: age || "11"
};
return dog;
}
createDog.getName = function(dog) {
// explicit dog as 1st parameter
alert(dog.name);
}
//createDog is a normal function that returns something, no "new" needed
var d1 = createDog("Rex", 8);
createDog.getName(d1);
// the original Animal class and sayName method
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
// define a Penguin class
function Penguin() {
this.name = "penguin";
this.numLegs = 2;
}
// set its prototype to be a new instance of Animal
var penguin = new Animal("Penguin", 2);
penguin.sayName();
The compiler asks me to "Create a new Penguin instance called penguin"...
not sure what I'm doing wrong here
Here's how to make a Penguin object that inherits from Animal using prototypal inheritance in javascript:
// the original Animal class and sayName method
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
// define a Penguin class
function Penguin() {
this.name = "penguin";
this.numLegs = 2;
}
// set its prototype to be a new instance of Animal
Penguin.prototype = new Animal();
// Create new Penguin
var penguin = new Penguin();
penguin.sayName(); // outputs "Hi my name is penguin"
var legCount = penguin.numLegs; // outputs 2
Here's an article that explains JavaScript Prototypal Inheritance in detail:
http://pietschsoft.com/post/2008/09/JavaScript-Prototypal-Inheritence-Explained-in-Simple-Terms
How do you access the this object from another object instance?
var containerObj = {
Person: function(name){
this.name = name;
}
}
containerObj.Person.prototype.Bag = function(color){
this.color = color;
}
containerObj.Person.prototype.Bag.getOwnerName(){
return name; //I would like to access the name property of this instance of Person
}
var me = new Person("Asif");
var myBag = new me.Bag("black");
myBag.getOwnerName()// Want the method to return Asif
Don't put the constructor on the prototype of another class. Use a factory pattern:
function Person(name) {
this.name = name;
}
Person.prototype.makeBag = function(color) {
return new Bag(color, this);
};
function Bag(color, owner) {
this.color = color;
this.owner = owner;
}
Bag.prototype.getOwnerName = function() {
return this.owner.name;
};
var me = new Person("Asif");
var myBag = me.makeBag("black");
myBag.getOwnerName() // "Asif"
Related patterns to deal with this problem: Prototype for private sub-methods, Javascript - Is it a bad idea to use function constructors within closures?