JavaScript: When to use a Class vs. a prototype?
So, what is the difference between using a class vs. a prototype like below and when do you use either approach?
To answer your question simply, there is no real difference.
Straight from the MDN web docs definition:
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.
Defining methods via prototype vs using this in the constructor - really a performance difference?
See http://jsperf.com/prototype-vs-this
Declaring your methods via the prototype is faster, but whether or not this is relevant is debatable.
If you have a performance bottleneck in your app it is unlikely to be this, unless you happen to be instantiating 10000+ objects on every step of some arbitrary animation, for example.
If performance is a serious concern, and you'd like to micro-optimise, then I would suggest declaring via prototype. Otherwise, just use the pattern that makes most sense to you.
I'll add that, in JavaScript, there is a convention of prefixing properties that are intended to be seen as private with an underscore (e.g. _process()
). Most developers will understand and avoid these properties, unless they're willing to forgo the social contract, but in that case you might as well not cater to them. What I mean to say is that: you probably don't really need true private variables...
Advantages of using prototype, vs defining methods straight in the constructor?
Methods that inherit via the prototype chain can be changed universally for all instances, for example:
function Class () {}
Class.prototype.calc = function (a, b) {
return a + b;
}
// Create 2 instances:
var ins1 = new Class(),
ins2 = new Class();
// Test the calc method:
console.log(ins1.calc(1,1), ins2.calc(1,1));
// -> 2, 2
// Change the prototype method
Class.prototype.calc = function () {
var args = Array.prototype.slice.apply(arguments),
res = 0, c;
while (c = args.shift())
res += c;
return res;
}
// Test the calc method:
console.log(ins1.calc(1,1,1), ins2.calc(1,1,1));
// -> 3, 3
Notice how changing the method applied to both instances? This is because ins1
and ins2
share the same calc()
function. In order to do this with public methods created during construction, you'd have to assign the new method to each instance that has been created, which is an awkward task. This is because ins1
and ins2
would have their own, individually created calc()
functions.
Another side effect of creating methods inside the constructor is poorer performance. Each method has to be created every time the constructor function runs. Methods on the prototype chain are created once and then "inherited" by each instance. On the flip side of the coin, public methods have access to "private" variables, which isn't possible with inherited methods.
As for your function Class() {}
vs var Class = function () {}
question, the former is "hoisted" to the top of the current scope before execution. For the latter, the variable declaration is hoisted, but not the assignment. For example:
// Error, fn is called before the function is assigned!
fn();
var fn = function () { alert("test!"); }
// Works as expected: the fn2 declaration is hoisted above the call
fn2();
function fn2() { alert("test!"); }
__proto__ VS. prototype in JavaScript
__proto__
is the actual object that is used in the lookup chain to resolve methods, etc. prototype
is the object that is used to build __proto__
when you create an object with new
:
( new Foo ).__proto__ === Foo.prototype
( new Foo ).prototype === undefined
What's the difference between this.function and prototype.function?
Functions on the prototype are only created once and shared between each instance. Functions created in the constructor are created as new objects for each new object created with the constructor.
As a general rule functions should be on the prototype since they will generally not be modified for different objects of the same type, and this has a slight memory/performance benefit. Other properties like objects and arrays should be defined in the constructor, unless you want to create a shared, static property, in which case you should use the prototype.
Its easier to see the distinctions with normal objects or arrays rather than functions
function Foo(){
this.bar = [];
}
var fooObj1 = new Foo();
var fooObj2 = new Foo();
fooObj1.bar.push("x");
alert(fooObj2.bar) //[]
as opposed to:
function Foo(){
}
Foo.prototype.bar = []
var fooObj1 = new Foo();
var fooObj2 = new Foo();
fooObj1.bar.push("x");
alert(fooObj2.bar) //["x"]
this Vs. prototype
Defining a function with whatever = function() { ... }
tends to create what's called a "closure", where the function can access local variables of the function that defines it. When you say this.fn = function() { ... }
, each object gets an instance of the function (and a new closure). This is often used to create "private" variables in Javascript, but comes with a cost: each function (in each object) is distinct, and takes up more memory.
When you say Rectangle.prototype.fn = function() { ... }
, one instance of the function is shared by all Rectangle
s. This saves memory, and can minimize some memory leaks in browsers that handle closures badly. If you don't need "private" members, or other such access to the defining function's local variables, it's usually a better idea.
JavaScript - The Good Parts: Function prototypes vs Object prototypes
You add a method to the Number
prototype, so every Number instance has access to it. In other words, because there's a property called "integer" on the Number prototype, any attempt to access that property from any Number instance will succeed. That's kind-of the whole point of putting properties on a constructor prototype.
When a JavaScript primitive number appears on the left side of a .
operator, the language automatically boxes it in a Number instance so that the method call makes sense.
edit — let's look at how that "method" function works. In the call
Number.method( "integer", function() { ... } )
what's going on? Well, inside the "method" function, the "name" parameter is "integer". The function parameter is then assigned as a property of this.prototype
. What is this
in that invocation of the "method" function? It's the Number constructor function. Thus, the "method" function — which is on the Function prototype, and therefore is available to all function instances, like the Number constructor function for example — adds the given function as a property of the prototype of the constructor function involved.
Why is the "method" property visible as a property of the Number constructor? Because the Number constructor is itself a function. The "method" function was created as a property of the Function prototype, so that means it is visible to every function instance — including the Number constructor.
Related Topics
Generating Random Whole Numbers in JavaScript in a Specific Range
Uncaught Referenceerror: $ Is Not Defined
How to Make the First Letter of a String Uppercase in JavaScript
Jquery: Return Data After Ajax Call Success
Difference Between a Function Expression VS Declaration in JavaScript
How May I Reference the Script Tag That Loaded the Currently-Executing Script
Should All Jquery Events Be Bound to $(Document)
Detecting an "Invalid Date" Date Instance in JavaScript
Convert Svg to Image (Jpeg, Png, etc.) in the Browser
JavaScript Window Resize Event
Use of 'Prototype' Vs. 'This' in JavaScript
How to Round to At Most 2 Decimal Places, If Necessary
Setstate Doesn't Update the State Immediately
Client on Node.Js: Uncaught Referenceerror: Require Is Not Defined
Uploading Both Data and Files in One Form Using Ajax
How to Add Two Strings as If They Were Numbers
How to Enable Cors in Angularjs
Can Scrapy Be Used to Scrape Dynamic Content from Websites That Are Using Ajax