Concept of subclassing in JS without using class [duplicate] - javascript

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.

Related

Which way is better to assign/create properties to an object via constructor? [duplicate]

So far I saw three ways for creating an object in JavaScript. Which way is best for creating an object and why?
I also saw that in all of these examples the keyword var is not used before a property — why? Is it not necessary to declare var before the name of a property as it mentioned that properties are variables?
In the second and third way, the name of the object is in upper-case whereas in the first way the name of the object is in lower-case. What case should we use for an object name?
First way:
function person(fname, lname, age, eyecolor){
this.firstname = fname;
this.lastname = lname;
this.age = age;
this.eyecolor = eyecolor;
}
myFather = new person("John", "Doe", 50, "blue");
document.write(myFather.firstname + " is " + myFather.age + " years old.");
Second way:
var Robot = {
metal: "Titanium",
killAllHumans: function(){
alert("Exterminate!");
}
};
Robot.killAllHumans();
Third way — JavaScript objects using array syntax:
var NewObject = {};
NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }
There is no best way, it depends on your use case.
Use way 1 if you want to create several similar objects. In your example, Person (you should start the name with a capital letter) is called the constructor function. This is similar to classes in other OO languages.
Use way 2 if you only need one object of a kind (like a singleton). If you want this object to inherit from another one, then you have to use a constructor function though.
Use way 3 if you want to initialize properties of the object depending on other properties of it or if you have dynamic property names.
Update: As requested examples for the third way.
Dependent properties:
The following does not work as this does not refer to book. There is no way to initialize a property with values of other properties in a object literal:
var book = {
price: somePrice * discount,
pages: 500,
pricePerPage: this.price / this.pages
};
instead, you could do:
var book = {
price: somePrice * discount,
pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;
Dynamic property names:
If the property name is stored in some variable or created through some expression, then you have to use bracket notation:
var name = 'propertyName';
// the property will be `name`, not `propertyName`
var obj = {
name: 42
};
// same here
obj.name = 42;
// this works, it will set `propertyName`
obj[name] = 42;
There is various way to define a function. It is totally based upon your requirement. Below are the few styles :-
Object Constructor
Literal constructor
Function Based
Protoype Based
Function and Prototype Based
Singleton Based
Examples:
Object constructor
var person = new Object();
person.name = "Anand",
person.getName = function(){
return this.name ;
};
Literal constructor
var person = {
name : "Anand",
getName : function (){
return this.name
}
}
function Constructor
function Person(name){
this.name = name
this.getName = function(){
return this.name
}
}
Prototype
function Person(){};
Person.prototype.name = "Anand";
Function/Prototype combination
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name
}
Singleton
var person = new function(){
this.name = "Anand"
}
You can try it on console, if you have any confusion.
There is no "best way" to create an object. Each way has benefits depending on your use case.
The constructor pattern (a function paired with the new operator to invoke it) provides the possibility of using prototypal inheritance, whereas the other ways don't. So if you want prototypal inheritance, then a constructor function is a fine way to go.
However, if you want prototypal inheritance, you may as well use Object.create, which makes the inheritance more obvious.
Creating an object literal (ex: var obj = {foo: "bar"};) works great if you happen to have all the properties you wish to set on hand at creation time.
For setting properties later, the NewObject.property1 syntax is generally preferable to NewObject['property1'] if you know the property name. But the latter is useful when you don't actually have the property's name ahead of time (ex: NewObject[someStringVar]).
Hope this helps!
I guess it depends on what you want. For simple objects, I guess you could use the second methods. When your objects grow larger and you're planning on using similar objects, I guess the first method would be better. That way you can also extend it using prototypes.
Example:
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getCircumference = function() {
return Math.PI * 2 * this.radius;
};
Circle.prototype.getArea = function() {
return Math.PI * this.radius * this.radius;
}
I am not a big fan of the third method, but it's really useful for dynamically editing properties, for example var foo='bar'; var bar = someObject[foo];.
There are a many ways to create your objects in JavaScript.
Using a constructer function to create an object or object literal notation is using alot in JavaScript. Also creating an instance of Object and then adding properties and methods to it, there are three common ways to do create objects in JavaScript.
Constructer functions
There are built-in constructer functions that we all may use them time to time, like Date(), Number(), Boolean() etc, all constructer functions start with Capital letter, in the meantime we can create custom constructor function in JavaScript like this:
function Box (Width, Height, fill) {
this.width = Width; // The width of the box
this.height = Height; // The height of the box
this.fill = true; // Is it filled or not?
}
and you can invoke it, simply using new(), to create a new instance of the constructor, create something like below and call the constructor function with filled parameters:
var newBox = new Box(8, 12, true);
Object literals
Using object literals are very used case creating object in JavaScript, this an example of creating a simple object, you can assign anything to your object properties as long as they are defined:
var person = {
name: "Alireza",
surname: "Dezfoolian"
nose: 1,
feet: 2,
hands: 2,
cash: null
};
Prototyping
After creating an Object, you can prototype more members to that, for example adding colour to our Box, we can do this:
Box.prototype.colour = 'red';
While many people here say there is no best way for object creation, there is a rationale as to why there are so many ways to create objects in JavaScript, as of 2019, and this has to do with the progress of JavaScript over the different iterations of EcmaScript releases dating back to 1997.
Prior to ECMAScript 5, there were only two ways of creating objects: the constructor function or the literal notation ( a better alternative to new Object()). With the constructor function notation you create an object that can be instantiated into multiple instances (with the new keyword), while the literal notation delivers a single object, like a singleton.
// constructor function
function Person() {};
// literal notation
var Person = {};
Regardless of the method you use, JavaScript objects are simply properties of key value pairs:
// Method 1: dot notation
obj.firstName = 'Bob';
// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';
// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
value: 'Bob',
writable: true,
configurable: true,
enumerable: false
})
// Method 4: Object.defineProperties
Object.defineProperties(obj, {
firstName: {
value: 'Bob',
writable: true
},
lastName: {
value: 'Smith',
writable: false
}
});
In early versions of JavaScript, the only real way to mimic class-based inheritance was to use constructor functions. the constructor function is a special function that is invoked with the 'new' keyword. By convention, the function identifier is capitalized, albiet it is not required. Inside of the constructor, we refer to the 'this' keyword to add properties to the object that the constructor function is implicitly creating. The constructor function implicitly returns the new object with the populated properties back to the calling function implicitly, unless you explicitly use the return keyword and return something else.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.sayName = function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var bob = new Person("Bob", "Smith");
bob instanceOf Person // true
There is a problem with the sayName method. Typically, in Object-Oriented Class-based programming languages, you use classes as factories to create objects. Each object will have its own instance variables, but it will have a pointer to the methods defined in the class blueprint. Unfortunately, when using JavaScript's constructor function, every time it is called, it will define a new sayName property on the newly created object. So each object will have its own unique sayName property. This will consume more memory resources.
In addition to increased memory resources, defining methods inside of the constructor function eliminates the possibility of inheritance. Again, the method will be defined as a property on the newly created object and no other object, so inheritance cannot work like. Hence, JavaScript provides the prototype chain as a form of inheritance, making JavaScript a prototypal language.
If you have a parent and a parent shares many properties of a child, then the child should inherit those properties. Prior to ES5, it was accomplished as follows:
function Parent(eyeColor, hairColor) {
this.eyeColor = eyeColor;
this.hairColor = hairColor;
}
Parent.prototype.getEyeColor = function() {
console.log('has ' + this.eyeColor);
}
Parent.prototype.getHairColor = function() {
console.log('has ' + this.hairColor);
}
function Child(firstName, lastName) {
Parent.call(this, arguments[2], arguments[3]);
this.firstName = firstName;
this.lastName = lastName;
}
Child.prototype = Parent.prototype;
var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair
The way we utilized the prototype chain above has a quirk. Since the prototype is a live link, by changing the property of one object in the prototype chain, you'd be changing same property of another object as well. Obviously, changing a child's inherited method should not change the parent's method. Object.create resolved this issue by using a polyfill. Thus, with Object.create, you can safely modify a child's property in the prototype chain without affecting the parent's same property in the prototype chain.
ECMAScript 5 introduced Object.create to solve the aforementioned bug in the constructor function for object creation. The Object.create() method CREATES a new object, using an existing object as the prototype of the newly created object. Since a new object is created, you no longer have the issue where modifying the child property in the prototype chain will modify the parent's reference to that property in the chain.
var bobSmith = {
firstName: "Bob",
lastName: "Smith",
sayName: function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var janeSmith = Object.create(bobSmith, {
firstName : { value: "Jane" }
})
console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.
Prior to ES6, here was a common creational pattern to utilize function constructors and Object.create:
const View = function(element){
this.element = element;
}
View.prototype = {
getElement: function(){
this.element
}
}
const SubView = function(element){
View.call(this, element);
}
SubView.prototype = Object.create(View.prototype);
Now Object.create coupled with constructor functions have been widely used for object creation and inheritance in JavaScript. However, ES6 introduced the concept of classes, which are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript. Thus, JavaScript remains a prototypal language.
ES6 classes make inheritance much easier. We no longer have to manually copy the parent class's prototype functions and reset the child class's constructor.
// create parent class
class Person {
constructor (name) {
this.name = name;
}
}
// create child class and extend our parent class
class Boy extends Person {
constructor (name, color) {
// invoke our parent constructor function passing in any required parameters
super(name);
this.favoriteColor = color;
}
}
const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue
All in all, these 5 different strategies of Object Creation in JavaScript coincided the evolution of the EcmaScript standard.
Of course there is a best way.Objects in javascript have enumerable and nonenumerable properties.
var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]
In the example above you can see that an empty object actually has properties.
Ok first let's see which is the best way:
var new_object = Object.create(null)
new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc
console.log("toString" in new_object) //=> false
In the example above the log will output false.
Now let's see why the other object creation ways are incorrect.
//Object constructor
var object = new Object();
console.log("toString" in object); //=> true
//Literal constructor
var person = {
name : "Anand",
getName : function (){
return this.name
}
}
console.log("toString" in person); //=> true
//function Constructor
function Person(name){
this.name = name
this.getName = function(){
return this.name
}
}
var person = new Person ('landi')
console.log("toString" in person); //=> true
//Prototype
function Person(){};
Person.prototype.name = "Anand";
console.log("toString" in person); //=> true
//Function/Prototype combination
function Person2(name){
this.name = name;
}
Person2.prototype.getName = function(){
return this.name
}
var person2 = new Person2('Roland')
console.log("toString" in person2) //=> true
As you can see above,all examples log true.Which means if you have a case that you have a for in loop to see if the object has a property will lead you to wrong results probably.
Note that the best way it is not easy.You have to define all properties of object line by line.The other ways are more easier and will have less code to create an object but you have to be aware in some cases.
I always use the "other ways" by the way and one solution to above warning if you don't use the best way is:
for (var property in new_object) {
if (new_object.hasOwnProperty(property)) {
// ... this is an own property
}
}
Majorly there are 3 ways of creating Objects-
Simplest one is using object literals.
const myObject = {}
Though this method is the simplest but has a disadvantage i.e if your object has behaviour(functions in it),then in future if you want to make any changes to it you would have to change it in all the objects.
So in that case it is better to use Factory or Constructor Functions.(anyone that you like)
Factory Functions are those functions that return an object.e.g-
function factoryFunc(exampleValue){
return{
exampleProperty: exampleValue
}
}
Constructor Functions are those functions that assign properties to objects using "this" keyword.e.g-
function constructorFunc(exampleValue){
this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);

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.

Which way is best for creating an object in JavaScript? Is `var` necessary before an object property?

So far I saw three ways for creating an object in JavaScript. Which way is best for creating an object and why?
I also saw that in all of these examples the keyword var is not used before a property — why? Is it not necessary to declare var before the name of a property as it mentioned that properties are variables?
In the second and third way, the name of the object is in upper-case whereas in the first way the name of the object is in lower-case. What case should we use for an object name?
First way:
function person(fname, lname, age, eyecolor){
this.firstname = fname;
this.lastname = lname;
this.age = age;
this.eyecolor = eyecolor;
}
myFather = new person("John", "Doe", 50, "blue");
document.write(myFather.firstname + " is " + myFather.age + " years old.");
Second way:
var Robot = {
metal: "Titanium",
killAllHumans: function(){
alert("Exterminate!");
}
};
Robot.killAllHumans();
Third way — JavaScript objects using array syntax:
var NewObject = {};
NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }
There is no best way, it depends on your use case.
Use way 1 if you want to create several similar objects. In your example, Person (you should start the name with a capital letter) is called the constructor function. This is similar to classes in other OO languages.
Use way 2 if you only need one object of a kind (like a singleton). If you want this object to inherit from another one, then you have to use a constructor function though.
Use way 3 if you want to initialize properties of the object depending on other properties of it or if you have dynamic property names.
Update: As requested examples for the third way.
Dependent properties:
The following does not work as this does not refer to book. There is no way to initialize a property with values of other properties in a object literal:
var book = {
price: somePrice * discount,
pages: 500,
pricePerPage: this.price / this.pages
};
instead, you could do:
var book = {
price: somePrice * discount,
pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;
Dynamic property names:
If the property name is stored in some variable or created through some expression, then you have to use bracket notation:
var name = 'propertyName';
// the property will be `name`, not `propertyName`
var obj = {
name: 42
};
// same here
obj.name = 42;
// this works, it will set `propertyName`
obj[name] = 42;
There is various way to define a function. It is totally based upon your requirement. Below are the few styles :-
Object Constructor
Literal constructor
Function Based
Protoype Based
Function and Prototype Based
Singleton Based
Examples:
Object constructor
var person = new Object();
person.name = "Anand",
person.getName = function(){
return this.name ;
};
Literal constructor
var person = {
name : "Anand",
getName : function (){
return this.name
}
}
function Constructor
function Person(name){
this.name = name
this.getName = function(){
return this.name
}
}
Prototype
function Person(){};
Person.prototype.name = "Anand";
Function/Prototype combination
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name
}
Singleton
var person = new function(){
this.name = "Anand"
}
You can try it on console, if you have any confusion.
There is no "best way" to create an object. Each way has benefits depending on your use case.
The constructor pattern (a function paired with the new operator to invoke it) provides the possibility of using prototypal inheritance, whereas the other ways don't. So if you want prototypal inheritance, then a constructor function is a fine way to go.
However, if you want prototypal inheritance, you may as well use Object.create, which makes the inheritance more obvious.
Creating an object literal (ex: var obj = {foo: "bar"};) works great if you happen to have all the properties you wish to set on hand at creation time.
For setting properties later, the NewObject.property1 syntax is generally preferable to NewObject['property1'] if you know the property name. But the latter is useful when you don't actually have the property's name ahead of time (ex: NewObject[someStringVar]).
Hope this helps!
I guess it depends on what you want. For simple objects, I guess you could use the second methods. When your objects grow larger and you're planning on using similar objects, I guess the first method would be better. That way you can also extend it using prototypes.
Example:
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getCircumference = function() {
return Math.PI * 2 * this.radius;
};
Circle.prototype.getArea = function() {
return Math.PI * this.radius * this.radius;
}
I am not a big fan of the third method, but it's really useful for dynamically editing properties, for example var foo='bar'; var bar = someObject[foo];.
There are a many ways to create your objects in JavaScript.
Using a constructer function to create an object or object literal notation is using alot in JavaScript. Also creating an instance of Object and then adding properties and methods to it, there are three common ways to do create objects in JavaScript.
Constructer functions
There are built-in constructer functions that we all may use them time to time, like Date(), Number(), Boolean() etc, all constructer functions start with Capital letter, in the meantime we can create custom constructor function in JavaScript like this:
function Box (Width, Height, fill) {
this.width = Width; // The width of the box
this.height = Height; // The height of the box
this.fill = true; // Is it filled or not?
}
and you can invoke it, simply using new(), to create a new instance of the constructor, create something like below and call the constructor function with filled parameters:
var newBox = new Box(8, 12, true);
Object literals
Using object literals are very used case creating object in JavaScript, this an example of creating a simple object, you can assign anything to your object properties as long as they are defined:
var person = {
name: "Alireza",
surname: "Dezfoolian"
nose: 1,
feet: 2,
hands: 2,
cash: null
};
Prototyping
After creating an Object, you can prototype more members to that, for example adding colour to our Box, we can do this:
Box.prototype.colour = 'red';
While many people here say there is no best way for object creation, there is a rationale as to why there are so many ways to create objects in JavaScript, as of 2019, and this has to do with the progress of JavaScript over the different iterations of EcmaScript releases dating back to 1997.
Prior to ECMAScript 5, there were only two ways of creating objects: the constructor function or the literal notation ( a better alternative to new Object()). With the constructor function notation you create an object that can be instantiated into multiple instances (with the new keyword), while the literal notation delivers a single object, like a singleton.
// constructor function
function Person() {};
// literal notation
var Person = {};
Regardless of the method you use, JavaScript objects are simply properties of key value pairs:
// Method 1: dot notation
obj.firstName = 'Bob';
// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';
// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
value: 'Bob',
writable: true,
configurable: true,
enumerable: false
})
// Method 4: Object.defineProperties
Object.defineProperties(obj, {
firstName: {
value: 'Bob',
writable: true
},
lastName: {
value: 'Smith',
writable: false
}
});
In early versions of JavaScript, the only real way to mimic class-based inheritance was to use constructor functions. the constructor function is a special function that is invoked with the 'new' keyword. By convention, the function identifier is capitalized, albiet it is not required. Inside of the constructor, we refer to the 'this' keyword to add properties to the object that the constructor function is implicitly creating. The constructor function implicitly returns the new object with the populated properties back to the calling function implicitly, unless you explicitly use the return keyword and return something else.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.sayName = function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var bob = new Person("Bob", "Smith");
bob instanceOf Person // true
There is a problem with the sayName method. Typically, in Object-Oriented Class-based programming languages, you use classes as factories to create objects. Each object will have its own instance variables, but it will have a pointer to the methods defined in the class blueprint. Unfortunately, when using JavaScript's constructor function, every time it is called, it will define a new sayName property on the newly created object. So each object will have its own unique sayName property. This will consume more memory resources.
In addition to increased memory resources, defining methods inside of the constructor function eliminates the possibility of inheritance. Again, the method will be defined as a property on the newly created object and no other object, so inheritance cannot work like. Hence, JavaScript provides the prototype chain as a form of inheritance, making JavaScript a prototypal language.
If you have a parent and a parent shares many properties of a child, then the child should inherit those properties. Prior to ES5, it was accomplished as follows:
function Parent(eyeColor, hairColor) {
this.eyeColor = eyeColor;
this.hairColor = hairColor;
}
Parent.prototype.getEyeColor = function() {
console.log('has ' + this.eyeColor);
}
Parent.prototype.getHairColor = function() {
console.log('has ' + this.hairColor);
}
function Child(firstName, lastName) {
Parent.call(this, arguments[2], arguments[3]);
this.firstName = firstName;
this.lastName = lastName;
}
Child.prototype = Parent.prototype;
var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair
The way we utilized the prototype chain above has a quirk. Since the prototype is a live link, by changing the property of one object in the prototype chain, you'd be changing same property of another object as well. Obviously, changing a child's inherited method should not change the parent's method. Object.create resolved this issue by using a polyfill. Thus, with Object.create, you can safely modify a child's property in the prototype chain without affecting the parent's same property in the prototype chain.
ECMAScript 5 introduced Object.create to solve the aforementioned bug in the constructor function for object creation. The Object.create() method CREATES a new object, using an existing object as the prototype of the newly created object. Since a new object is created, you no longer have the issue where modifying the child property in the prototype chain will modify the parent's reference to that property in the chain.
var bobSmith = {
firstName: "Bob",
lastName: "Smith",
sayName: function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var janeSmith = Object.create(bobSmith, {
firstName : { value: "Jane" }
})
console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.
Prior to ES6, here was a common creational pattern to utilize function constructors and Object.create:
const View = function(element){
this.element = element;
}
View.prototype = {
getElement: function(){
this.element
}
}
const SubView = function(element){
View.call(this, element);
}
SubView.prototype = Object.create(View.prototype);
Now Object.create coupled with constructor functions have been widely used for object creation and inheritance in JavaScript. However, ES6 introduced the concept of classes, which are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript. Thus, JavaScript remains a prototypal language.
ES6 classes make inheritance much easier. We no longer have to manually copy the parent class's prototype functions and reset the child class's constructor.
// create parent class
class Person {
constructor (name) {
this.name = name;
}
}
// create child class and extend our parent class
class Boy extends Person {
constructor (name, color) {
// invoke our parent constructor function passing in any required parameters
super(name);
this.favoriteColor = color;
}
}
const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue
All in all, these 5 different strategies of Object Creation in JavaScript coincided the evolution of the EcmaScript standard.
Of course there is a best way.Objects in javascript have enumerable and nonenumerable properties.
var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]
In the example above you can see that an empty object actually has properties.
Ok first let's see which is the best way:
var new_object = Object.create(null)
new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc
console.log("toString" in new_object) //=> false
In the example above the log will output false.
Now let's see why the other object creation ways are incorrect.
//Object constructor
var object = new Object();
console.log("toString" in object); //=> true
//Literal constructor
var person = {
name : "Anand",
getName : function (){
return this.name
}
}
console.log("toString" in person); //=> true
//function Constructor
function Person(name){
this.name = name
this.getName = function(){
return this.name
}
}
var person = new Person ('landi')
console.log("toString" in person); //=> true
//Prototype
function Person(){};
Person.prototype.name = "Anand";
console.log("toString" in person); //=> true
//Function/Prototype combination
function Person2(name){
this.name = name;
}
Person2.prototype.getName = function(){
return this.name
}
var person2 = new Person2('Roland')
console.log("toString" in person2) //=> true
As you can see above,all examples log true.Which means if you have a case that you have a for in loop to see if the object has a property will lead you to wrong results probably.
Note that the best way it is not easy.You have to define all properties of object line by line.The other ways are more easier and will have less code to create an object but you have to be aware in some cases.
I always use the "other ways" by the way and one solution to above warning if you don't use the best way is:
for (var property in new_object) {
if (new_object.hasOwnProperty(property)) {
// ... this is an own property
}
}
Majorly there are 3 ways of creating Objects-
Simplest one is using object literals.
const myObject = {}
Though this method is the simplest but has a disadvantage i.e if your object has behaviour(functions in it),then in future if you want to make any changes to it you would have to change it in all the objects.
So in that case it is better to use Factory or Constructor Functions.(anyone that you like)
Factory Functions are those functions that return an object.e.g-
function factoryFunc(exampleValue){
return{
exampleProperty: exampleValue
}
}
Constructor Functions are those functions that assign properties to objects using "this" keyword.e.g-
function constructorFunc(exampleValue){
this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);

Categories