How to clone a constructor in JavaScript? - javascript

I have a constructor Monkey():
function Monkey(name, age) {
this.name = name;
this.age = age;
}
I want to make another constructor named Human() with an extra property cars which will store number of cars the person has along with all the property that Monkey has (like name and age)
I don't want to repeat all the Monkey stuff in the new Human stuff. Is is possible to clone the Monkey and extend a property with prototype?

I've tried this code, I guess it's what you want:
function Human(name,age,cars){
Monkey.call(this,name,age);
this.cars = cars;
}
This way, the Human constructor calls the Monkey constructor as a normal function, but setting its namespace as the new Human object. Thus, in this case, the this keyword inside Monkey constructor refers to a object of class Human, and not Monkey. Also, with this code, the condition new Human() instanceof Human; returns true, since I'm not returning a new instance of Monkey, just using its constructor.
Also, you can "clone" the prototype, as you said. Just do this:
Human.prototype = Monkey.prototype;
EDIT
As #Bergi amd suggested, the best way to clone a prototype is using the Object.create method, as follows:
Human.prototype = Object.create(Monkey.prototype, {constructor:{value:Human}});

I'm writing this answer simply to complement the others, it SHOULD NOT be used unless you fully know the impact of using the non-standard __proto__.
function Monkey(name, age) {
this.name = name;
this.age = age;
}
function Human(name, age, cars) {
this.__proto__ = new Monkey(name, age);
this.cars = cars;
}
console.log(new Human(1, 2, 3));
See also
__proto__, when will it be gone? Alternatives?
JavaScript and __proto__ - what browsers use it?

Simple start for functional style/parasitic'ish inheritance:
function Human(name, age, cars) {
var that = new Monkey(name, age);
that.cars = cars;
return that;
}
As outlined by Douglas Crockford
http://www.crockford.com/javascript/inheritance.html

Related

Concept of subclassing in JS without using class [duplicate]

This question already has answers here:
Proper Prototypal Inheritance
(3 answers)
Closed last year.
I am looking to learn about class inheritance and how it may be emulated without using the class keyword. It's just an academic/learning exercise.
Does the following method work for doing class inheritance, or am I missing some core concepts?
function Person(name, age) {
let person = Object.create(Person.prototype);
person.name = name;
person.age = age;
return person;
}
Person.prototype.get_birth_year = function() {
console.log(new Date().getFullYear() - this.age);
}
function Kid(name, age, dad, mom) {
let kid = Object.create(Person.prototype);
kid.dad = dad;
kid.mom = mom;
for (let key in Kid.prototype) {
kid[key] = Kid.prototype[key];
}
return kid;
}
Kid.prototype.callMom = function() {
console.log(`MOM!!! (${this.mom})`);
}
function KidToy(name, age, dad, mom, toyname) {
let toy = Object.create(Kid.prototype);
toy.toyname = toyname;
for (let key in KidToy.prototype) {
toy[key] = KidToy.prototype[key];
}
return toy;
}
KidToy.prototype.findToy = function() {
console.log('Looking to find the', this.toyname);
}
let p = Person('Bob', 33);
p.get_birth_year();
let k = Kid('Billy', 12, 'Bob', 'Margot');
k.callMom();
let t = KidToy('Billy', 12, 'Bob', 'Margot', 'Potatohead');
t.findToy();
The only things I'm doing here to subclass are:
Create an object with the parent prototype.
Iterate through the current prototype and tack on those properties to the object.
Or, am I missing some things?
Not quite. There are three approaches to prototypal inheritance in JS:
Using the new keyword with a function that acts as a constructor, and assigning methods to that function's .prototype so they are inherited by the instances created by it.
Using the Object.create function to manually create objects that inherit from others.
Using the class, constructor and super syntax to write classical-style code in JS. JS classes can only be instantiated with the new keyword and support some unique features, though they still use prototypal inheritance underneath.
When you call a function with the new keyword, it automatically creates an object that inherits from the function's .prototype and exposes it as this within the function body.
function Person(name, age) {
this.name = name;
this.age = age;
}
const john = new Person("John", 42);
You don't need to create the instance and return it, this is all done by the new keyword. Objects like john above will have access to all properties stored in Person.prototype that aren't shadowed by properties assigned to john itself.
Person.prototype is itself an object that was created automagically when the Person function was defined. It inherits from Object and it has one property, constructor, which points back to the Person function.
A few more corrections about your assumptions:
let kid = Object.create(Person.prototype);
With this code, kid does not inherit from Kid.prototype.
for (let key in Kid.prototype) {
kid[key] = Kid.prototype[key];
}
This code copies all the enumerable properties of Kid.prototype into kid at the time of creation. This means that if you ever add properties to Kid.prototype later, they won't be in kid. If kidactually inherited fromKid.prototype, methods could be added to Kid.prototype` even after a kid instance was created, and that instance would inherit those methods.
Instead, you probably wanted something like this:
function Kid(name, age, dad, mom) {
// invoke super constructor
Person.call(this, name, age);
this.dad = dad;
this.mom = mom;
}
// Kid extends Person
Kid.prototype = Object.create(Person.prototype);
Kid.prototype.constructor = Kid;
All kid instances created after this code will inherit not from the default Kid.prototype which itself inherits from Object, but from our custom-made Kid.prototype which inherits from Person.prototype.
As you can see, this isn't very intuitive or practical, which is why class syntax was added to the language.
Hopefully this gives you a push in the right direction. I personally rarely use inheritance in my own code, and instead adopt a more FP approach with closures and composition.

Should we include methods in prototypes for ES6 Classes for performance?

So as I learn more about the Prototypal Inheritance in JS, I read the following in MDN article (read lines just above this link)
Note that when we are calling our constructor function, we are defining greeting() every time, which isn't ideal. To avoid this, we can define functions on the prototype instead, which we will look at later.
The idea recommended is to add properties on Function and methods on the prototype (read here)
Person.prototype.farewell = function() {
alert(this.name.first + ' has left the building. Bye for now!');
};
I read at multiple places that this way
The object creation is faster, since the farewell is not created for every object creation. This is because it is created once and attached to the prototype, and all the objects link to the prototype.
The methods are looked up on the prototypal chain so every object links to the same method on the prototype.
Now comes the ES6 class. I have the following code
class Person {
constructor(first, last, age, gender, interests) {
this.name = {
first: first,
last: last
};
this.age = age;
this.gender = gender;
this.interests = interests;
}
greeting () {
console.log("Hi! I am", this.name.first);
}
farewell () {
console.log(this.name.first, "has left the building. Bye for now!");
}
}
It seems that with this approach greeting and farewell will be created again (following up on same logic as Functions since class is a syntactic sugar)
So, I changed the class to
class Person {
constructor(first, last, age, gender, interests) {
this.name = {
first: first,
last: last
};
this.age = age;
this.gender = gender;
this.interests = interests;
}
}
Person.prototype.greeting = function () {
console.log("Hi! I am", this.name.first);
}
Person.prototype.farewell = function () {
console.log(this.name.first, "has left the building. Bye for now!");
}
Question
1. Does the latter way (Adding methods on prototype in ES6 class) is a recommended way?
2. Does the logic of class and traditional new Function to create a new object align? Copy vs Method on Prototype?
Please let me know if there is anything else I am missing
Thanks
UPDATE
After few answers, I retried my examples and confirmed the answers. My code looks like
class Phone {
constructor(company, name, color, price) {
this.company = company;
this.name = name;
this.color = color;
this.price = price;
}
print() {
console.log(this.company, this.name, this.color, this.price);
}
}
class Apple extends Phone {
constructor(name, color, price) {
super("Apple", name, color, price);
this.companyWork = "ClosedSource";
}
}
let iPhone11 = new Apple("iPhone11", "black", 900);
iPhone11.print()
After I ran this code, I can confirm that print() is available on Phone.prototype
As you've already discovered, class definitions put methods on the prototype. You asked for a reference so here's a little code you can run to see for yourself:
class Person {
constructor(first, last, age, gender, interests) {
this.name = {
first: first,
last: last
};
this.age = age;
this.gender = gender;
this.interests = interests;
}
greeting () {
console.log("Hi! I am", this.name.first);
}
farewell () {
console.log(this.name.first, "has left the building. Bye for now!");
}
}
let p = new Person("Jack", "Beanstalk", 201, "giant", ["crushing things", "stomping things"]);
console.log("Person", Object.getOwnPropertyNames(Person));
console.log("p", Object.getOwnPropertyNames(p));
let p_prototype = Object.getPrototypeOf(p);
console.log("p_prototype === Person.prototype is ", p_prototype === Person.prototype);
console.log("Person.prototype", Object.getOwnPropertyNames(Person.prototype));
That generates this output:
Person [ 'length', 'prototype', 'name' ]
p [ 'name', 'age', 'gender', 'interests' ]
p_prototype === Person.prototype is true
Person.prototype [ 'constructor', 'greeting', 'farewell' ]
So, you can draw these conclusions:
The Person class has only the expected properties for a constructor function and the prototype object, none of the class-defined methods are there.
An instance of the class has only the expected data properties that are assigned in the constructor, none of the class-defined methods are on the object itself.
The prototype you get from an instance is the same as the prototype of the class (thus no new object is created for each instance).
The Person.prototype has the expected methods from the class definition on it plus a property that points to the constructor itself (used in inheriting and calling derived constructor).
So, you can verify from this that methods defined with the class syntax go on the Classname.prototype object and that object is shared with all instances.
AFAIK
No, it's not a recommended way. Class methods are created as methods on prototype. In other words classes are just syntactic sugar for regular prototypal inheritance.
In both cases methods won't be created multiple times if multiple objects are created. Methods will be created only once.

Javascript not inheriting prototype properties

Why won't Javascript inherit the properties from a prototype
Example
function Man(name,age,color){
this.name = name;
this.age = age;
this.color = color;
}
boy = function Boy(){};
boy.prototype = new Man();
myboy = new boy('hari',14,'blue');
console.log(myboy);
// => myboy {name:undefined, age:undefined, color:undefined}
It does not inherit the properties.
Its meant to have the properties
// => myboy {name:'hari', age:14, color:'blue'}
It does not inherit the properties.
Yes it does, it clearly has name, age and color. They just don't have any values because you are calling Man without any arguments, and Boy doesn't do anything with the arguments you provided.
Your inheritance setup is simply incorrect. You should add the parent prototype to the prototype chain of the child using Object.create:
Boy.prototype = Object.create(
Man.prototype,
{constructor: {value: Boy, writable: true}}
);
And, like in other languages, you have to call the parent constructor inside the child constructor (applied to the new child instance), passing along all the needed argumants:
function Boy(name, age, color) {
Man.call(this, name, age, color);
}
// or
function Boy() {
Man.apply(this, arguments);
}
More info:
Benefits of using `Object.create` for inheritance
Inheritance revisited

Javascript Prototype Inheritance and Chaining Constructs for an Object

When reading https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call for the section "Using call to chain constructors for an object":
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0)
throw RangeError('Cannot create product "' + name + '" with a negative price');
return this;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
Food.prototype = Object.create(Product.prototype);
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
Toy.prototype = Object.create(Product.prototype);
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
I have read that a object's prototype is actually a object itself that points to the constructor's properties memory locations.
In function Food(name, price) it inherits the constructor's Product's properties with Product.call(this). What is Food.prototype = Object.create(Product.prototype); doing? Is it adding another prototype to Food(if that is even possible to have 2 prototypes)? Or is it appending to Food's prototype with the same prototype values of Product(which it already inherited so doesn't make sense to me ether)?
The essence of the problem cam be summarized as "why would you need to set prototypes at all"? In other words, why this is not sufficient to call the base class constructor and not to set the prototype?
The trick is that you could possibly not set the child class function's prototype! Your trivial example would work fine without it. Comment out the line and you will find that the code works with and without this line:
Food.prototype = Object.create(Product.prototype);
This is because all your object properties are set in constructors and by chaining constructors (calling the base class constructor) you have all the properties set on child class instances.
Consider however this:
function Base() {
this.BaseClassMethod = function() {}
}
vs
function Base() {
}
Base.prototype.BaseClassMethod = function() {}
As you can see, there are no fields but a method. Semantically, both snippets define a constructor function that creates instances having the sole BaseClassMethod method. However, in the first snippet there is a new extra function created for each created instance of the class, while in the second snippet the method definition is shared.
This very simple example shows that the same semantics can be achieved in different ways that have different profiles - in the above example is was at least the different memory footprint.
Yet another difference between these two is that in the latter, the function can be redefined somewhere in the future and the new version affects all previously created instances while in the first snippet what you can do is to change the definition in specific instances but not easily "in all previously created instances".
Whether or not this is your goal is another story. You can freely choose between these two ways of assigning methods to classes.
And there lies the answer to your question: without setting the prototype chain, methods defined in base class prototype (the latter snippet) would not be inherited if you only called the base class constructor from the child class constructor.
In other words, calling both the base class constructor and setting the prototype chain makes your inheritance independent on the way methods are defined in the base class.
Let's let code speak for itself. Object.create basically does this:
Object.create = function (o) {
//Object.create equals an anonymous function that accepts one parameter, 'o'.
function F() {};
//Create a new function called 'F' which is just an empty object.
F.prototype = o;
//the prototype of the 'F' function should point to the
//parameter of the anonymous function.
return new F();
//create a new constructor function based off of the 'F' function.
};
Hope this helps. Cheers
Food.prototype = Object.create(Product.prototype) is like extends in other languages. Product.call(this) is like super. With a helper and following conventions it helps to see this relation:
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype); // inherit parent's prototype
this.prototype.constructor = this; // point to the right constructor
};
// A "class"
var Product = (function(){
// constructor
function Product(name, price) {
this.name = name;
this.price = price;
}
return Product;
}());
var Food = (function(_super){
Food.inherits(Product); // inherit Product's prototype methods
function Food(name, price) {
// call "super" to inherit instance properties
_super.call(this, name, price);
this.category = 'food';
}
}(Product)); // the parent class AKA "super"
It is not 100% equivalent, but this should give you a general idea of how inheritance works in JS compared to other languages. It can look pretty similar as you see.
In function Food(name, price) it inherits the constructor's Product's properties with Product.call(this).
Not really. It applies the Product's constructor to the new Food instance, executing its code with e.g. the negative price check.
A "byproduct" is that the constructor creates instance-specific properties on the object, yes.
What is Food.prototype = Object.create(Product.prototype); doing? Is it adding another prototype to Food(if that is even possible to have 2 prototypes)?
Exactly. It is chaining the prototypes. The instances of Food that are created by new Food will inherit properties (including methods) from Food.prototype, which will (by that statement) inherit properties from Product.prototype.
You can't see much of this behaviour currently as your prototype objects do not have any methods yet. Add some (maybe an "output" method?) and check the results.
Simple minimalistic inheritance library: (2kb minified) https://github.com/haroldiedema/joii
It basically allows you to do the following (and more):
// First (bottom level)
var Person = new Class(function() {
this.name = "Unknown Person";
});
// Employee, extend on Person & apply the Role property.
var Employee = new Class({ extends: Person }, function() {
this.name = 'Unknown Employee';
this.role = 'Employee';
this.getValue = function() {
return "Hello World";
}
});
// 3rd level, extend on Employee. Modify existing properties.
var Manager = new Class({ extends: Employee }, function() {
// Overwrite the value of 'role'.
this.role = this.role + ': Manager';
// Class constructor to apply the given 'name' value.
this.__construct = function(name) {
this.name = name;
}
// Parent inheritance & override
this.getValue = function() {
return this.parent.getValue().toUpperCase();
}
});
// And to use the final result:
var myManager = new Manager("John Smith");
console.log( myManager.name ); // John Smith
console.log( myManager.role ); // Manager
console.log( myManager.getValue() ); // HELLO WORLD

javascript prototyped inheritance and object properties

I'm trying to apply prototyped inheritance to a function in Javascript. It's all pretty plain and even described in Wikipedia's javascript lemma. It works if my properties are simple javascript types:
function Person() {
this.age = 0;
this.location = {
x: 0,
y: 0,
absolute: false
};
};
function Employee() {};
Employee.prototype = new Person();
Employee.prototype.celebrate = function () {
this.age++;
}
var pete = new Employee();
pete.age = 5;
pete.celebrate();
var bob = new Employee();
bob.celebrate();
console.log("bob is " + bob.age + " pete is " + pete.age);
With Employee.prototype = new Person();, all Person's properties and (prototyped) methods are inherited by Employee, which is fundamental to inheritance.
This works as expected: bob is 1 pete is 6
Now I'm starting to fiddle with pete's location (after celebrating)
pete.celebrate();
pete.location.absolute=true;
Displaying bob.location.absolute shows: true, which is contra intuitive (I didn't touch bob's location so I expect it to have the initial value declared in Person) and ruins my solution.
In my initial understanding this should have been false. I do realize that I probably should clone the location object from the initial Person, but I'm not sure where or how to do this.
And if there are maybe better techniques for inheritance?
When you instantiate a new Employee, all properties of Person are copied. As this is a shallow copy, pete and bob share the same location object. For your problem, there does not seems a very good solution. You can either use a framework or do a hack like this:
function Employee() { Person.apply(this); };
This calls the Person constructor in the context of the this object.
The MDC has more info on this: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply
Don't run the Person constructor when inheriting, an Employee shouldn't
even have a .location because it's not in Person.prototype.
function createObject( fn ){
function f(){}
f.prototype = fn.prototype;
return new f;
}
Then:
Employee.prototype = createObject( Person );
This will inherit properly without side effects (running constructor).
You would only run the parent constructor in the child constructor:
function Employee() {
Person.apply( this, arguments );
}
I ran into similar issue. I ended up using a separate constructor for the internal object.
function engine(cc, fuel) {
this.cc = cc;
this.fuel = fuel
}
function car(type, model, cc, fuel) {
this.type = type;
this.model = model;
this.engine = new engine(cc, fuel);
}
var mycar = new car("sedan", "toyota corolla", 1500, "gas");
console.log(mycar.type);
//sedan
console.log(mycar.engine.cc);
//1500
If I had any methods on the prototypes of 'engine' or 'car' constructors, they would still be available. However, I am not deriving the "car" class from the "engine" class in OOP sense. I didn't need to. The "engine" is used as a component of "car".
Meanwhile, for inheritance, I prefer to use the new methods incorporated in ECMAScript 5 which means using Object.create, Object.defineProperties, etc. They are supported even in IE9. Before that I used the same 'apply()' method suggested by Kosta.

Categories