Reputation: 36650
Doing some literature review about how Objects are created in JS here is what I got so far:
// Using ES6 classes
class Animal1 {
constructor(name) {
this.name = name;
}
}
let fluffy = new Animal1("fluffy");
// Using constructor functions
function Animal2(name) {
this.name = name;
}
let puppy = new Animal2("puppy");
// Using Object.create
function createBunny(name) {
let bunnyObj = Object.create(Object.prototype);
bunnyObj.name = name;
return bunnyObj;
}
let bunny = createBunny("bunny");
// Using object literal
function createKitten(name) {
let kittenObj = {
name: name
};
return kittenObj;
}
let kitten = createKitten("kitten");
console.dir(fluffy);
console.dir(puppy);
console.dir(bunny);
console.dir(kitten);
Where the console.dir got the following output:
I read that ES6
classes are just syntactic sugar which are doing basically the same thing as the constructor function (second way of creating objects in my example)
To me these methods all look the same, since they all create Objects which have
0bject as __proto__
property. Are there any differences in these Objects besides that the objects created with the new
keyword are named differently? For instance is there a difference in performance in creating objects in a different manner?
Upvotes: 3
Views: 118
Reputation: 35491
The class constructor does a bit more than the function constructor.
A class is meant to be declarative, safety layer on top of a normal function, restricting you to only use the function for instantiating objects using new
and doing inheritance (via the prototype) with the extends
and super
keywords.
Regular functions can do pretty much everything a class does, except in a more verbose manner and without restrictions. This allows more flexibility but also increases the potential of bugs.
There are a few other notable differences:
new B() // <-- this is fine cause B is hoisted
function B(){}
new A() // <-- doesn't exist cause A's not hoisted
class A{}
class A {
constructor() {
b = 5; // assigning to a global is an error in strict mode
}
}
c = 5 // <-- assigning to a global outside of a class is fine since no strict mode
new A()
new
):class A {
constructor(){}
}
A() // Uncaught TypeError: Class constructor A cannot be invoked without 'new'
All of this additional "syntactic sugar" on top of classes, due to the fact that it does a certain amount of work, would naturally lead to some theoretical performance penalty. That being said, this isn't really significant and shouldn't matter for 99.99% of usages out there.
What really matters about classes is to understand that they are just a prettier layer over existing functionality and that they do not create a new OOP system in JS. It's just (somewhat subjectively) a nicer syntax.
Object.create
and object literals allow us to easily instantiate JS objects on the fly. What Object.create
does as opposed to using a literal like {}
, is that it actually creates a new object whose prototype is the object you give it. Using just {}
on the other hand does nothing to prototypes (every {}
by default has Object.prototype
as its prototype), just creates an object instance.
This means that your given usage of Object.create(Object.prototype)
and {}
are practically equivalent, where the former is a more verbose version of the latter.
Based concretely on your 4 examples, all 4 objects created are effectively the same.
Upvotes: 4