JavaScript/jQuery extend function which takes parameter [duplicate] - javascript

I am attempting to pass a test suite utilizing inheritance through JavaScript. Below is a snippet of the code I have so far:
var Infant = function() {
this.age = 0;
this.color = 'pink';
this.food = 'milk';
};
Infant.prototype.eat = function(){
return this.eat;
}
var Adolescent = function() {
this.age = 5;
this.height = 'short';
this.job = 'keep on growing';
};
I would like to inherit the food property from the Infant class and the eat method but my attempts have fallen short. my initial thought was to assign this.Adolescent = Infant.food; but that didn't work. I know I need to set Infant as the Superclass but I'm spinning my wheels

When using constructor functions for inheritance in JavaScript, you:
Make the prototype property of the "derived" constructor an object whose prototype is the prototype property of the "base" constructor.
Set the constructor property on the "derived" constructor's prototype property to point to the "derived" constructor.
Call the "base" constructor from the "derived" constructor with the correct this.
Like this:
var Infant = function() {
this.age = 0;
this.color = 'pink';
this.food = 'milk';
};
Infant.prototype.eat = function(){
return /*...something...*/; // Returning `this.eat` doesn't make any sense, that's the function we're in
};
var Adolescent = function() {
// #3 Give super a chance to initialize the instance, you can pass args if appropriate
Infant.call(this);
this.age = 5;
this.height = 'short';
this.job = 'keep on growing';
};
// Set up Adolescent's prototype, which uses Infant's prototype property as its prototype
Adolescent.prototype = Object.create(Infant.prototype); // #1
Object.defineProperty(Adolescent.prototype, "constructor", // #2
value: Adolescent,
writable: true,
configurable: true
});
// (In pre-ES5 environments that don't event have `Object.defineProperty`, you'd use
// an assignment instead: `Adolescent.prototype.constructor = Adolescent;`
Object.create was added in ES5, so it won't be present on obsolete JavaScript engines like the one in IE8. The single-argument version of it used above can be easily shimmed, though.
In ES2015 we have the option of doing it with the new class semantics:
class Infant {
constructor() {
this.age = 0;
this.color = 'pink';
this.food = 'milk';
}
eat() {
return /*...something...*/;
}
}
class Adolescent extends Infant { // extends does #1 and #2
constructor() {
super(); // #3, you can pass args here if appropriate
this.age = 5;
this.height = 'short';
this.job = 'keep on growing';
}
}

Related

Add functions to super class that will be used by the subclass also

I'm pretty new to JS and it seems everything seems to have so many ways to do that will make you confused.Anyways this is what I am trying to do:
//SuperClass
function Animal(name, origin, type) {
this.name = name;
this.origin = origin;
this.type = type;
//Some function that does something
this.makeSound = function() {
return "foo";
}
}
function Mamal(name, origin, type, weight, height) {
Animal.call(this, name, origin, type);
this.weight = weight;
this.height = height;
this.makeSound = function() {
return "I am a Mamal";
}
}
So the question is how would I add a function to the Animal class AFTER
it has been declared so that the Mamal class (or whatever subclass) also inherits it and can use it.
If I understand your question correctly, what you actually want to achieve is that the Mamal class inherits methods from the Animal class? As in your question you have referred to them as Classes, I have provided an example with classes, rather than functions.
If so, you can declare Mamal like so:
class Mamal extends Animal {
constructor(weight, height) {
super();
this.weight = weight;
this.height = height;
}
// if you want to execute the Animal implementation of makeSound
makeSound() {
return super.makeSound();
}
// if you want to overwrite the Animal implementation of makeSound
makeSound() {
return "I am a mammal";
}
}
The extends keyword is used in class declarations or class expressions
to create a class as a child of another class.
Sub classing with extends
Super class calls with super
Update
Find the prototypal inheritance alternative here:
function Animal(name, origin, type) {
this.name = name;
this.origin = origin;
this.type = type;
}
Animal.prototype.makeSound = function () {
return "foo";
};
function Mammal(weight, height) {
this.weight = weight;
this.height = height;
Animal.call(this); // call super constructor.
}
Mammal.prototype = Object.create(Animal.prototype); //inherit the Animal object through the prototype chain
Mammal.prototype.makeSound = function () {
return "I am a mammal";
}; //Overwrite the makeSound method inherited from Animal
const cheetah = new Animal('cheetah', 'Africa', 'mammal');
cheetah.makeSound();
//foo
const mammal = new Mammal('100kg', '1m');
mammal.makeSound();
//I am a mammal

JavaScript Inheritance prototypical

Why do we need to set prototype object for inheritance when we can directly inherit parent properties if we call the constructor method using this in each child function?
function Employee() {
this.name = "";
this.dept = "general";
}
function Manager() {
Employee.call(this);
this.reports = [];
}
Manager.prototype = Object.create(Employee.prototype);
We can use inheritence even if we don't set prototype of Manager as Employee.
Usually prototypes are used to put functions/methods on them, not properties, because with properties you'll have a single property value shared between all object instances. Also, you may not need to set prototype for inheritance if you add methods inside a constructor. For example:
function Employee(name) {
this.name = "";
this.dept = "general";
this.reportName = function() {return this.name};
}
function Manager(name) {
Employee.call(this, name);
this.reports = [];
}
var manager = new Manager('Peter');
manager.reportName(); // Peter
However, adding methods/function inside object's constructor is inefficient, since every time a constructor is called an instance of a function is created. So usually, all methods, not properties, are allocated on prototype like this:
function Employee(name) {
this.name = "";
this.dept = "general";
}
Employee.prototype.reportName = function() {return this.name};
Now, in this case, simply calling a constructor won't be enough:
function Manager(name) {
Employee.call(this, name);
this.reports = [];
}
var manager = new Manager('Peter');
manager.reportName(); // throws an error
You need to set a prototype:
Manager.prototype = Object.create(Employee.prototype)
var manager = new Manager('Peter');
manager.reportName(); // 'Peter'

JS using class variable [duplicate]

Can JavaScript classes/objects have constructors? How are they created?
Using prototypes:
function Box(color) // Constructor
{
this.color = color;
}
Box.prototype.getColor = function()
{
return this.color;
};
Hiding "color" (somewhat resembles a private member variable):
function Box(col)
{
var color = col;
this.getColor = function()
{
return color;
};
}
Usage:
var blueBox = new Box("blue");
alert(blueBox.getColor()); // will alert blue
var greenBox = new Box("green");
alert(greenBox.getColor()); // will alert green
Here's a template I sometimes use for OOP-similar behavior in JavaScript. As you can see, you can simulate private (both static and instance) members using closures. What new MyClass() will return is an object with only the properties assigned to the this object and in the prototype object of the "class."
var MyClass = (function () {
// private static
var nextId = 1;
// constructor
var cls = function () {
// private
var id = nextId++;
var name = 'Unknown';
// public (this instance only)
this.get_id = function () { return id; };
this.get_name = function () { return name; };
this.set_name = function (value) {
if (typeof value != 'string')
throw 'Name must be a string';
if (value.length < 2 || value.length > 20)
throw 'Name must be 2-20 characters long.';
name = value;
};
};
// public static
cls.get_nextId = function () {
return nextId;
};
// public (shared across instances)
cls.prototype = {
announce: function () {
alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
}
};
return cls;
})();
I've been asked about inheritance using this pattern, so here goes:
// It's a good idea to have a utility class to wire up inheritance.
function inherit(cls, superCls) {
// We use an intermediary empty constructor to create an
// inheritance chain, because using the super class' constructor
// might have side effects.
var construct = function () {};
construct.prototype = superCls.prototype;
cls.prototype = new construct;
cls.prototype.constructor = cls;
cls.super = superCls;
}
var MyChildClass = (function () {
// constructor
var cls = function (surName) {
// Call super constructor on this instance (any arguments
// to the constructor would go after "this" in call(…)).
this.constructor.super.call(this);
// Shadowing instance properties is a little bit less
// intuitive, but can be done:
var getName = this.get_name;
// public (this instance only)
this.get_name = function () {
return getName.call(this) + ' ' + surName;
};
};
inherit(cls, MyClass); // <-- important!
return cls;
})();
And an example to use it all:
var bob = new MyClass();
bob.set_name('Bob');
bob.announce(); // id is 1, name shows as "Bob"
var john = new MyChildClass('Doe');
john.set_name('John');
john.announce(); // id is 2, name shows as "John Doe"
alert(john instanceof MyClass); // true
As you can see, the classes correctly interact with each other (they share the static id from MyClass, the announce method uses the correct get_name method, etc.)
One thing to note is the need to shadow instance properties. You can actually make the inherit function go through all instance properties (using hasOwnProperty) that are functions, and automagically add a super_<method name> property. This would let you call this.super_get_name() instead of storing it in a temporary value and calling it bound using call.
For methods on the prototype you don't need to worry about the above though, if you want to access the super class' prototype methods, you can just call this.constructor.super.prototype.methodName. If you want to make it less verbose you can of course add convenience properties. :)
It seems to me most of you are giving example of getters and setters not a constructor, ie http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming).
lunched-dan was closer but the example didn't work in jsFiddle.
This example creates a private constructor function that only runs during the creation of the object.
var color = 'black';
function Box()
{
// private property
var color = '';
// private constructor
var __construct = function() {
alert("Object Created.");
color = 'green';
}()
// getter
this.getColor = function() {
return color;
}
// setter
this.setColor = function(data) {
color = data;
}
}
var b = new Box();
alert(b.getColor()); // should be green
b.setColor('orange');
alert(b.getColor()); // should be orange
alert(color); // should be black
If you wanted to assign public properties then the constructor could be defined as such:
var color = 'black';
function Box()
{
// public property
this.color = '';
// private constructor
var __construct = function(that) {
alert("Object Created.");
that.color = 'green';
}(this)
// getter
this.getColor = function() {
return this.color;
}
// setter
this.setColor = function(color) {
this.color = color;
}
}
var b = new Box();
alert(b.getColor()); // should be green
b.setColor('orange');
alert(b.getColor()); // should be orange
alert(color); // should be black
So what is the point of "constructor"
property? Cannot figure out where it
could be useful, any ideas?
The point of the constructor property is to provide some way of pretending JavaScript has classes. One of the things you cannot usefully do is change an object's constructor after it's been created. It's complicated.
I wrote a fairly comprehensive piece on it a few years ago: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
Example here: http://jsfiddle.net/FZ5nC/
Try this template:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Name = Name||{};
Name.Space = Name.Space||{};
//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Name.Space.ClassName = function Name_Space_ClassName(){}
//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Name.Space.ClassName.prototype = {
v1: null
,v2: null
,f1: function Name_Space_ClassName_f1(){}
}
//============================================================
// Static Variables
//------------------------------------------------------------
Name.Space.ClassName.staticVar = 0;
//============================================================
// Static Functions
//------------------------------------------------------------
Name.Space.ClassName.staticFunc = function Name_Space_ClassName_staticFunc(){
}
</script>
You must adjust your namespace if you are defining a static class:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
Shape.Rectangle = Shape.Rectangle||{};
// In previous example, Rectangle was defined in the constructor.
</script>
Example class:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Shape = Shape||{};
//============================================================
// Constructor - MUST BE AT TOP OF FILE
//------------------------------------------------------------
Shape.Rectangle = function Shape_Rectangle(width, height, color){
this.Width = width;
this.Height = height;
this.Color = color;
}
//============================================================
// Member Functions & Variables
//------------------------------------------------------------
Shape.Rectangle.prototype = {
Width: null
,Height: null
,Color: null
,Draw: function Shape_Rectangle_Draw(canvasId, x, y){
var canvas = document.getElementById(canvasId);
var context = canvas.getContext("2d");
context.fillStyle = this.Color;
context.fillRect(x, y, this.Width, this.Height);
}
}
//============================================================
// Static Variables
//------------------------------------------------------------
Shape.Rectangle.Sides = 4;
//============================================================
// Static Functions
//------------------------------------------------------------
Shape.Rectangle.CreateSmallBlue = function Shape_Rectangle_CreateSmallBlue(){
return new Shape.Rectangle(5,8,'#0000ff');
}
Shape.Rectangle.CreateBigRed = function Shape_Rectangle_CreateBigRed(){
return new Shape.Rectangle(50,25,'#ff0000');
}
</script>
Example instantiation:
<canvas id="painting" width="500" height="500"></canvas>
<script>
alert("A rectangle has "+Shape.Rectangle.Sides+" sides.");
var r1 = new Shape.Rectangle(16, 12, "#aa22cc");
r1.Draw("painting",0, 20);
var r2 = Shape.Rectangle.CreateSmallBlue();
r2.Draw("painting", 0, 0);
Shape.Rectangle.CreateBigRed().Draw("painting", 10, 0);
</script>
Notice functions are defined as A.B = function A_B(). This is to make your script easier to debug. Open Chrome's Inspect Element panel, run this script, and expand the debug backtrace:
<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};
//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}
Fail.Test();
</script>
This is a constructor:
function MyClass() {}
When you do
var myObj = new MyClass();
MyClass is executed, and a new object is returned of that class.
Yes, you can define a constructor inside a class declaration like this:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
I found this tutorial very useful. This approach is used by most of jQuery plug-ins.
http://www.htmlgoodies.com/html5/tutorials/create-an-object-oriented-javascript-class-constructor.html#fbid=OVYAQL_TDpK
var Class = function(methods) {
var klass = function() {
this.initialize.apply(this, arguments);
};
for (var property in methods) {
klass.prototype[property] = methods[property];
}
if (!klass.prototype.initialize) klass.prototype.initialize = function(){};
return klass;
};
Now ,
var Person = Class({
initialize: function(name, age) {
this.name = name;
this.age = age;
},
toString: function() {
return "My name is "+this.name+" and I am "+this.age+" years old.";
}
});
var alice = new Person('Alice', 26);
alert(alice.name); //displays "Alice"
alert(alice.age); //displays "26"
alert(alice.toString()); //displays "My name is Alice and I am 26 years old" in most browsers.
//IE 8 and below display the Object's toString() instead! "[Object object]"
This pattern has served me well. With this pattern, you create classes in separate files, load them into your overall app "as needed".
// Namespace
// (Creating new if not instantiated yet, otherwise, use existing and just add to it)
var myApp = myApp || {};
// "Package"
// Similar to how you would establish a package in other languages
(function() {
// "Class"
var MyClass = function(params) {
this.initialize(params);
}
// "Private Static" vars
// - Only accessible to functions in this class.
// - Doesn't get wiped out when we create a new instance.
var countInstances = 0;
var allInstances = [];
// "Private Static" functions
// - Same as above, but it's a function accessible
// only to other functions in this class.
function doSomething(){
}
// "Public Static" vars
// - Everyone has access.
// - Doesn't get wiped out when we create a new instance.
MyClass.counter = 0;
// "Public Static" functions
// - Same as above, but anyone can call this "static method".
// - Kinda like a singleton class situation.
MyClass.foobar = function(){
}
// Public properties and methods are built into the "prototype"
// - This is how each instance can become unique unto itself.
// - Establishing "p" as "local" (Static Private) variable
// simply so we don't have to keep typing "MyClass.prototype"
// for each property and function.
var p = MyClass.prototype;
// "Public" vars
p.id = null;
p.firstname = null;
p.lastname = null;
// "Private" vars
// - Only used by "this" instance.
// - There isn't "true" privacy for each
// instance so we have to fake it.
// - By tradition, we indicate "privacy"
// by prefixing it with an underscore.
// - So technically, anyone can access, but we simply
// don't tell anyone about it (e.g. in your API)
// so no one knows about it :)
p._foo = null;
p.initialize = function(params){
this.id = MyClass.counter++;
this.firstname = params.firstname;
this.lastname = params.lastname;
MyClass.counter++;
countInstances++;
allInstances.push(this);
}
p.doAlert = function(theMessage){
alert(this.firstname + " " + this.lastname + " said: " + theMessage + ". My id:" + this.id + ". Total People:" + countInstances + ". First Person:" + allInstances[0].firstname + " " + allInstances[0].lastname);
}
// Assign class to app
myApp.MyClass = MyClass;
// Close the "Package"
}());
// Usage example:
var bob = new myApp.MyClass({ firstname : "bob",
lastname : "er"
});
bob.doAlert("hello there");
I guess I'll post what I do with javascript closure since no one is using closure yet.
var user = function(id) {
// private properties & methods goes here.
var someValue;
function doSomething(data) {
someValue = data;
};
// constructor goes here.
if (!id) return null;
// public properties & methods goes here.
return {
id: id,
method: function(params) {
doSomething(params);
}
};
};
Comments and suggestions to this solution are welcome. :)
Maybe it's gotten a little simpler, but below is what I've come up with now in 2017:
class obj {
constructor(in_shape, in_color){
this.shape = in_shape;
this.color = in_color;
}
getInfo(){
return this.shape + ' and ' + this.color;
}
setShape(in_shape){
this.shape = in_shape;
}
setColor(in_color){
this.color = in_color;
}
}
In using the class above, I have the following:
var newobj = new obj('square', 'blue');
//Here, we expect to see 'square and blue'
console.log(newobj.getInfo());
newobj.setColor('white');
newobj.setShape('sphere');
//Since we've set new color and shape, we expect the following: 'sphere and white'
console.log(newobj.getInfo());
As you can see, the constructor takes in two parameters, and we set the object's properties. We also alter the object's color and shape by using the setter functions, and prove that its change remained upon calling getInfo() after these changes.
A bit late, but I hope this helps. I've tested this with a mocha unit-testing, and it's working well.
Using Nick's sample above, you can create a constructor for objects without parameters using a return statement as the last statement in your object definition. Return your constructor function as below and it will run the code in __construct each time you create the object:
function Box()
{
var __construct = function() {
alert("Object Created.");
this.color = 'green';
}
this.color = '';
this.getColor = function() {
return this.color;
}
__construct();
}
var b = new Box();
They do if you use Typescript - open source from MicroSoft :-)
class BankAccount {
balance: number;
constructor(initially: number) {
this.balance = initially;
}
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}
Typescript lets you 'fake' OO constructs that are compiled into javascript constructs. If you're starting a large project it may save you a lot of time and it just reached milestone 1.0 version.
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
The above code gets 'compiled' to :
var BankAccount = (function () {
function BankAccount(initially) {
this.balance = initially;
}
BankAccount.prototype.deposit = function (credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
In JavaScript the invocation type defines the behaviour of the function:
Direct invocation func()
Method invocation on an object obj.func()
Constructor invocation new func()
Indirect invocation func.call() or func.apply()
The function is invoked as a constructor when calling using new operator:
function Cat(name) {
this.name = name;
}
Cat.prototype.getName = function() {
return this.name;
}
var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
Any instance or prototype object in JavaScript have a property constructor, which refers to the constructor function.
Cat.prototype.constructor === Cat // => true
myCat.constructor === Cat // => true
Check this post about constructor property.
While using Blixt's great template from above, I found out that it doesn't work well with multi-level inheritance (MyGrandChildClass extending MyChildClass extending MyClass) – it cycles on calling first parent's constructor over and over. So here is a simple workaround – if you need multi-level inheritance, instead of using this.constructor.super.call(this, surName); use chainSuper(this).call(this, surName); with the chain function defined like this:
function chainSuper(cls) {
if (cls.__depth == undefined) cls.__depth = 1; else cls.__depth++;
var depth = cls.__depth;
var sup = cls.constructor.super;
while (depth > 1) {
if (sup.super != undefined) sup = sup.super;
depth--;
}
return sup;
}
http://www.jsoops.net/ is quite good for oop in Js. If provide private, protected, public variable and function, and also Inheritance feature. Example Code:
var ClassA = JsOops(function (pri, pro, pub)
{// pri = private, pro = protected, pub = public
pri.className = "I am A ";
this.init = function (var1)// constructor
{
pri.className += var1;
}
pub.getData = function ()
{
return "ClassA(Top=" + pro.getClassName() + ", This=" + pri.getClassName()
+ ", ID=" + pro.getClassId() + ")";
}
pri.getClassName = function () { return pri.className; }
pro.getClassName = function () { return pri.className; }
pro.getClassId = function () { return 1; }
});
var newA = new ClassA("Class");
//***Access public function
console.log(typeof (newA.getData));
// function
console.log(newA.getData());
// ClassA(Top=I am A Class, This=I am A Class, ID=1)
//***You can not access constructor, private and protected function
console.log(typeof (newA.init)); // undefined
console.log(typeof (newA.className)); // undefined
console.log(typeof (newA.pro)); // undefined
console.log(typeof (newA.getClassName)); // undefined
just to offer up some variety. ds.oop is a nice way to declare classes with constructors in javascript. It supports every possible type of inheritance (Including 1 type that even c# does not support) as well as Interfaces which is nice.
var Color = ds.make.class({
type: 'Color',
constructor: function (r,g,b) {
this.r = r; /* now r,g, and b are available to */
this.g = g; /* other methods in the Color class */
this.b = b;
}
});
var red = new Color(255,0,0); // using the new keyword to instantiate the class
Here we need to notice one point in java script, it is a class-less language however,we can achieve it by using functions in java script. The most common way to achieve this we need to create a function in java script and use new keyword to create an object and use this keyword to define property and methods.Below is the example.
// Function constructor
var calculator=function(num1 ,num2){
this.name="This is function constructor";
this.mulFunc=function(){
return num1*num2
};
};
var objCal=new calculator(10,10);// This is a constructor in java script
alert(objCal.mulFunc());// method call
alert(objCal.name);// property call
//Constructors With Prototypes
var calculator=function(){
this.name="Constructors With Prototypes";
};
calculator.prototype.mulFunc=function(num1 ,num2){
return num1*num2;
};
var objCal=new calculator();// This is a constructor in java script
alert(objCal.mulFunc(10,10));// method call
alert(objCal.name); // property call
In most cases you have to somehow declare the property you need before you can call a method that passes in this information. If you do not have to initially set a property you can just call a method within the object like so. Probably not the most pretty way of doing this but this still works.
var objectA = {
color: '';
callColor : function(){
console.log(this.color);
}
this.callColor();
}
var newObject = new objectA();

JavaScript Extending Class

I have a base class:
function Monster() {
this.health = 100;
}
Monster.prototype.growl = function() {
console.log("Grr!");
}
That I want to extend and create another class with:
function Monkey extends Monster() {
this.bananaCount = 5;
}
Monkey.prototype.eatBanana {
this.bananaCount--;
this.health++; //Accessing variable from parent class monster
this.growl(); //Accessing function from parent class monster
}
I've done quite a bit of research and there appears to be many convoluted solutions for doing this in JavaScript. What would be the simplest and most reliable way of accomplishing this in JS?
Updated below for ES6
March 2013 and ES5
This MDN document describes extending classes well:
https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
In particular, here is now they handle it:
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);
}
// inherit Person
Student.prototype = Object.create(Person.prototype);
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Note that Object.create() is unsupported in some older browsers, including IE8:
If you are in the position of needing to support these, the linked MDN document suggests using a polyfill, or the following approximation:
function createObject(proto) {
function ctor() { }
ctor.prototype = proto;
return new ctor();
}
Using this like Student.prototype = createObject(Person.prototype) is preferable to using new Person() in that it avoids calling the parent's constructor function when inheriting the prototype, and only calls the parent constructor when the inheritor's constructor is being called.
May 2017 and ES6
Thankfully, the JavaScript designers have heard our pleas for help and have adopted a more suitable way of approaching this issue.
MDN has another great example on ES6 class inheritance, but I'll show the exact same set of classes as above reproduced in ES6:
class Person {
sayHello() {
alert('hello');
}
walk() {
alert('I am walking!');
}
}
class Student extends Person {
sayGoodBye() {
alert('goodBye');
}
sayHello() {
alert('hi, I am a student');
}
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Clean and understandable, just like we all want. Keep in mind, that while ES6 is pretty common, it's not supported everywhere:
ES6 gives you now the opportunity to use class & extends keywords :
Then , your code will be :
You have a base class:
class Monster{
constructor(){
this.health = 100;
}
growl() {
console.log("Grr!");
}
}
That You want to extend and create another class with:
class Monkey extends Monster {
constructor(){
super(); //don't forget "super"
this.bananaCount = 5;
}
eatBanana() {
this.bananaCount--;
this.health++; //Accessing variable from parent class monster
this.growl(); //Accessing function from parent class monster
}
}
Try this:
Function.prototype.extends = function(parent) {
this.prototype = Object.create(parent.prototype);
};
Monkey.extends(Monster);
function Monkey() {
Monster.apply(this, arguments); // call super
}
Edit: I put a quick demo here http://jsbin.com/anekew/1/edit. Note that extends is a reserved word in JS and you may get warnings when linting your code, you can simply name it inherits, that's what I usually do.
With this helper in place and using an object props as only parameter, inheritance in JS becomes a bit simpler:
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype);
};
function Monster(props) {
this.health = props.health || 100;
}
Monster.prototype = {
growl: function() {
return 'Grrrrr';
}
};
Monkey.inherits(Monster);
function Monkey() {
Monster.apply(this, arguments);
}
var monkey = new Monkey({ health: 200 });
console.log(monkey.health); //=> 200
console.log(monkey.growl()); //=> "Grrrr"
If you don't like the prototype approach, because it doesn't really behave in a nice OOP-way, you could try this:
var BaseClass = function()
{
this.some_var = "foobar";
/**
* #return string
*/
this.someMethod = function() {
return this.some_var;
}
};
var MyClass = new Class({ extends: BaseClass }, function()
{
/**
* #param string value
*/
this.__construct = function(value)
{
this.some_var = value;
}
})
Using lightweight library (2k minified): https://github.com/haroldiedema/joii
I can propose one variant, just have read in book, it seems the simplest:
function Parent() {
this.name = 'default name';
};
function Child() {
this.address = '11 street';
};
Child.prototype = new Parent(); // child class inherits from Parent
Child.prototype.constructor = Child; // constructor alignment
var a = new Child();
console.log(a.name); // "default name" trying to reach property of inherited class
This is an extension (excuse the pun) of elclanrs' solution to include detail on instance methods, as well as taking an extensible approach to that aspect of the question; I fully acknowledge that this is put together thanks to David Flanagan's "JavaScript: The Definitive Guide" (partially adjusted for this context). Note that this is clearly more verbose than other solutions, but would probably benefit in the long-term.
First we use David's simple "extend" function, which copies properties to a specified object:
function extend(o,p) {
for (var prop in p) {
o[prop] = p[prop];
}
return o;
}
Then we implement his Subclass definition utility:
function defineSubclass(superclass, // Constructor of our superclass
constructor, // Constructor of our new subclass
methods, // Instance methods
statics) { // Class properties
// Set up the prototype object of the subclass
constructor.prototype = Object.create(superclass.prototype);
constructor.prototype.constructor = constructor;
if (methods) extend(constructor.prototype, methods);
if (statics) extend(constructor, statics);
return constructor;
}
For the last bit of preparation we enhance our Function prototype with David's new jiggery-pokery:
Function.prototype.extend = function(constructor, methods, statics) {
return defineSubclass(this, constructor, methods, statics);
};
After defining our Monster class, we do the following (which is re-usable for any new Classes we want to extend/inherit):
var Monkey = Monster.extend(
// constructor
function Monkey() {
this.bananaCount = 5;
Monster.apply(this, arguments); // Superclass()
},
// methods added to prototype
{
eatBanana: function () {
this.bananaCount--;
this.health++;
this.growl();
}
}
);
For traditional extending you can simply write superclass as constructor function,
and then apply this constructor for your inherited class.
function AbstractClass() {
this.superclass_method = function(message) {
// do something
};
}
function Child() {
AbstractClass.apply(this);
// Now Child will have superclass_method()
}
Example on angularjs:
http://plnkr.co/edit/eFixlsgF3nJ1LeWUJKsd?p=preview
app.service('noisyThing',
['notify',function(notify){
this._constructor = function() {
this.scream = function(message) {
message = message + " by " + this.get_mouth();
notify(message);
console.log(message);
};
this.get_mouth = function(){
return 'abstract mouth';
}
}
}])
.service('cat',
['noisyThing', function(noisyThing){
noisyThing._constructor.apply(this)
this.meow = function() {
this.scream('meooooow');
}
this.get_mouth = function(){
return 'fluffy mouth';
}
}])
.service('bird',
['noisyThing', function(noisyThing){
noisyThing._constructor.apply(this)
this.twit = function() {
this.scream('fuuuuuuck');
}
}])
For Autodidacts:
function BaseClass(toBePrivate){
var morePrivates;
this.isNotPrivate = 'I know';
// add your stuff
}
var o = BaseClass.prototype;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';
// MiddleClass extends BaseClass
function MiddleClass(toBePrivate){
BaseClass.call(this);
// add your stuff
var morePrivates;
this.isNotPrivate = 'I know';
}
var o = MiddleClass.prototype = Object.create(BaseClass.prototype);
MiddleClass.prototype.constructor = MiddleClass;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';
// TopClass extends MiddleClass
function TopClass(toBePrivate){
MiddleClass.call(this);
// add your stuff
var morePrivates;
this.isNotPrivate = 'I know';
}
var o = TopClass.prototype = Object.create(MiddleClass.prototype);
TopClass.prototype.constructor = TopClass;
// add your prototype stuff
o.stuff_is_never_private = 'whatever_except_getter_and_setter';
// to be continued...
Create "instance" with getter and setter:
function doNotExtendMe(toBePrivate){
var morePrivates;
return {
// add getters, setters and any stuff you want
}
}
Summary:
There are multiple ways which can solve the problem of extending a constructor function with a prototype in Javascript. Which of these methods is the 'best' solution is opinion based. However, here are two frequently used methods in order to extend a constructor's function prototype.
ES 2015 Classes:
class Monster {
constructor(health) {
this.health = health
}
growl () {
console.log("Grr!");
}
}
class Monkey extends Monster {
constructor (health) {
super(health) // call super to execute the constructor function of Monster
this.bananaCount = 5;
}
}
const monkey = new Monkey(50);
console.log(typeof Monster);
console.log(monkey);
The above approach of using ES 2015 classes is nothing more than syntactic sugar over the prototypal inheritance pattern in javascript. Here the first log where we evaluate typeof Monster we can observe that this is function. This is because classes are just constructor functions under the hood. Nonetheless you may like this way of implementing prototypal inheritance and definitively should learn it. It is used in major frameworks such as ReactJS and Angular2+.
Factory function using Object.create():
function makeMonkey (bananaCount) {
// here we define the prototype
const Monster = {
health: 100,
growl: function() {
console.log("Grr!");}
}
const monkey = Object.create(Monster);
monkey.bananaCount = bananaCount;
return monkey;
}
const chimp = makeMonkey(30);
chimp.growl();
console.log(chimp.bananaCount);
This method uses the Object.create() method which takes an object which will be the prototype of the newly created object it returns. Therefore we first create the prototype object in this function and then call Object.create() which returns an empty object with the __proto__ property set to the Monster object. After this we can initialize all the properties of the object, in this example we assign the bananacount to the newly created object.
the absolutely minimal (and correct, unlike many of the answers above) version is:
function Monkey(param){
this.someProperty = param;
}
Monkey.prototype = Object.create(Monster.prototype);
Monkey.prototype.eatBanana = function(banana){ banana.eat() }
That's all. You can read here the longer explanation

Problem using the prototype chain

If I have a constructor that takes a number of arguments:
var Mammal = function(name, weight) {
this.name = name;
this.weight = weight;
}
Mammal.prototype.makeSound = function(sound) {
alert(sound);
}
Mammal.prototype.getName = function() {
return this.name;
}
and I want to do some inheritence:
var Human = function(name,weight,language,location) {
//code
}
Human.prototype = new Mammal();
In the last line here isn't the Human prototype getting assigned undefined for the name and weight parameters? I see this code all the time....I know that the Human constructor is being fed the name and weight params but it seems messy that the prototype is getting these undefined values. I know this only works because javascript is slack enough to allow you to do this. Is there a way to get round this?
What bothers you exactly?
Human.prototype = new Mammal();
alert( Human.prototype.name ); // undefined
alert( Human.prototype.foo ); // undefined
You can consider them as not being there. The reason why you're not writing:
Human.prototype = Mammal.prototype;
Is because the Mammal constructor can add methods that are not on the prototype object.
var Mammal = function(name, weight) {
this.name = name;
this.weight = weight;
this.somefun = function() {
// this can't be inhereted by
// Mammal.prototype
}
}
In order not to reapeat yourself you can use Constructor Chaining:
var Human = function(name,weight,language,location) {
this.language = language;
this.location = location;
// call parent constructor
Mammal.apply(this, arguments);
}
This seems to be more straightforward, isn't it? You call the parent constructor to deal with the name and weight parameters, and you only care about Human specific things in the Human constructor.
i think i've seen something like this once:
var Human = function(name,weight,language,location) {
Mammal.call(this, name, weight);//calls the parent constructor
this.language = language;
this.lcoaiton = location;
}
Human.prototype = new Mammal();

Categories

Resources