Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 months ago.
This post was edited and submitted for review 3 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Duplication Notes
This question does not talk about methods defined in classes.
Problem
When I use classes to define object: when I use the object's method as callback the this pointer does not point the object itself anymore.
Example
class MyClass {
bar = 'my bar';
foo() {
console.log(this.bar);
}
}
function runCallback(func) {
return func();
}
const myClass = new MyClass();
// Output: 'my bar' (as expected)
myClass.foo()
// Output: 'undefined' (unexpected)
runCallback(myClass.foo)
Question
How can I make Javascript use the correct value of this (= the object the method belongs to).
Javascript knowledge
The Problem happens, because this in Javascript means something different than in other languages.
This answer is a community Wiki. Please add further ways of dealing with the problem as you find them.
Solutions without salt grains
None as of now
Accept, that Javascript does not support classes in the common way.
Solutions that come with a grain of salt
Use arrow-functions on callback
runCallback((...params) => myClass.foo(...params))
Use bind on methods when used as callback
runCallback(myClass.foo.bind(myClass))
Why does it work?
this for foo gets specifically set to myClass
Problems:
Fragility: Might be easy to forget binding.
Blackbox principle break: The correctness of method foo will depend on how it is called, not how it is defined (however, note that this was the case to begin with)
Readability: Code gets longer
Use bind on methods during creation
class MyClass {
bar = 'my bar';
constructor(){
this.foo = this.foo.bind(this);
}
foo() {
console.log(this.bar);
}
}
Reference: https://stackoverflow.com/questions/56503531/what-is-a-good-way-to-automatically-bind-js-class-methods
Problems:
Maintenance: You need bind methods inside the constructor
Fragility: It's easy to forget binding on (new) methods
Memory: Functions will turn to per-instance functions (i.e. each object has their own function object)
use auto-bind
Available as library, or implement it yourself (see below)
class MyClass {
bar = 'my bar';
constructor() {
autoBind(this);
}
foo() {
return String(this.bar);
}
}
Problems:
Memory: Functions will turn to per-instance functions (i.e. each object has their own function object)
Fragility: Don't forget to call autoBind
Implemenation of autoBind:
/**
* Gets all non-builtin properties up the prototype chain.
**/
const _getAllProperties = (object) => {
const properties: any = [];
do {
for (const key of Reflect.ownKeys(object)) {
properties.push({ obj: object, key: key });
}
} while ((object = Reflect.getPrototypeOf(object)) && object !== Object.prototype);
return properties;
};
function autoBind(self) {
const props = _getAllProperties(self.constructor.prototype);
props.forEach((prop) => {
if (prop.key === 'constructor') {
return;
}
const descriptor = Reflect.getOwnPropertyDescriptor(prop.obj, prop.key);
if (descriptor && typeof descriptor.value === 'function') {
self[prop.key] = self[prop.key].bind(self);
}
});
return self;
}
Use fields and Arrow functions
class MyClass3 implements MyInterface {
bar = 'my bar';
foo = () => {
console.log(this.bar);
};
}
Why does it work?
Arrow functions are automatically bound (reference)
Problems:
Problems with arrow functions in class fields
Not Mockable
Inheritance won't work as expected
Memory: Functions will turn to per-instance functions (i.e. each object has their own function object)function implementation (as opposed to one implemenation for all objects).
I have some old code that I would like to refactor and improve, currently the code looks something like this:
function objFunction1(obj){
//do something
console.log(obj, 1);
}
function objFunction2(obj){
//do something else
console.log(obj, 2)
}
var obj = {test: true};
objFunction1(obj);
objFunction2(obj);
I am thinking of makeing it into a class eg:
class item{
constructor(test){
this.test = test;
return this;
}
function1(){
console.log(this, 1);
}
function2(){
console.log(this, 2);
}
}
var obj = new item(true);
obj.function1();
obj.function2();
How does JavaScript handle this? if I was to have 10,000 instances of item does JavaScript duplicate those methods for each instance or does it just store a reference to the class declaration?
what I am basically asking, is my original code more efficient?
If you have 100000 or any number of objects, but function1 and function2 will have only single copy in its prototype
Since class syntax is just syntactic sugar over the old function constructor. When you write above class syntax then the methods are declared in the prototype of that class and you can verify it as:
const obj1 = new item(true);
const obj2 = new item(false);
obj1.function1 === obj2.function1;
If obj1.function1 === obj2.function1 expression returns true then that means, there is only one function that is defined in its prototype
You should read docs
class item {
constructor(test) {
this.test = test;
return this;
}
function1() {
console.log(this, 1);
}
function2() {
console.log(this, 2);
}
}
const obj1 = new item(true);
const obj2 = new item(false);
console.log(obj1.function1 === obj2.function1); // true
Note: I've capitalize the first-letter of constructor function that externally specifies that it is a constructor function. It is just a convention used in JS community
The above class syntax will be equal to the following function constructor syntax as:
function function1() {
console.log(this, 1);
}
function function2() {
console.log(this, 2);
}
function Item(test) {
this.test = test;
}
Item.prototype.function1 = function1;
Item.prototype.function2 = function2;
const obj1 = new Item(true);
const obj2 = new Item(false);
console.log(obj1);
console.log(obj2);
console.log(obj1.function1 === obj2.function1);
The short answer is: no.
The functions would not be duplicated; only one definition for each function would be created as the objects' prototype.
JavaScript uses prototype-based inheritance, which means that objects have a prototype that "contain" the methods shared by all the objects from the same prototype:
JavaScript is often described as a prototype-based language — to
provide inheritance, objects can have a prototype object, which acts
as a template object that it inherits methods and properties from.
(source: Mozilla)
If you declare two objects using the same "class" you can see that their instances are different but the methods are the same
var objA = new item(true);
var objB = new item(true);
objA === objB // false
objA.function1 === objA.function // true
You can access to the prototype of the object by using the somewhat deprecated (but still supported by Chrome) __proto__ property:
objA.__proto__ === objB.__proto__ // true
So in terms of both memory and execution time, the two options are probably nearly identical.
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);
I am a beginner learning JavaScript. Reading through this page, I can't understand how this piece of code is defining an object. I expect the " foo: bar" construct and not sure if __proto__ is a builtin name or doing something special here. What is going on?
In ES2015, object literals are extended to support setting the prototype at construction, shorthand for foo: foo assignments, defining methods, making super calls, and computing property names with expressions. Together, these also bring object literals and class declarations closer together, and let object-based design benefit from some of the same conveniences. MDN
var obj = {
// __proto__
__proto__: theProtoObj,
// Shorthand for ‘handler: handler’
handler,
// Methods
toString() {
// Super calls
return "d " + super.toString();
},
// Computed (dynamic) property names
[ 'prop_' + (() => 42)() ]: 42
};
That code snippet is really a bunch of syntactic sugar for plain old key: value notation.
__proto__: theProtoObj,
Yes, this is a special field, not just an arbitrary name. It is the object used when searching up the inheritance tree. Its' explicit use is generally discouraged. Read this Quora answer for a better understanding of it.
handler,
This is syntactic sugar for handler: handler. Frequently do you want to have a field in an object and assign it a value from a variable with the same name, so they included that shorthand in the specification.
var x = 10;
var y = 15;
// longhand
var point = { x: x, y: y };
// shorthand
var point = { x, y };
toString() {
This is syntactic sugar for:
var obj = {
toString: function () {
...
}
};
return "d " + super.toString();
The super keyword makes calling functions from a parent class much more clear. Where before it would look something like this:
var Person = function (name) {
this.name = name;
}
var Engineer = function (name) {
// "super call"
Person.call(this, name);
this.profession = 'Engineer';
}
Now it can look like this:
class Engineer extends Person {
constructor (name) {
super(name);
this.profession = 'Engineer';
}
}
[ 'prop_' + (() => 42)() ]: 42
Probably my favorite. This syntax allows you to have dynamic key names in the object literal. Before, you would have to do this:
var obj = {};
obj['prop_' + 42] = 42;
But, with the dynamic literal syntax, you can do this:
var obj = {
['prop_' + 42]: 42
};
(() => 42)()
Syntactic sugar for:
// create an anonymous function and call it immediately
(function () {
return 42;
})();
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);