4

Difference between methods of defining JavaScript classes

 3 years ago
source link: https://www.codesd.com/item/difference-between-methods-of-defining-javascript-classes.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

What's the difference between these two method of defining a 'class' in JavaScript?

Method One

Define method within the constructor:

function MyClass()
{
    this.foo = function() { console.log('hello world!'); };
}

Method Two

Define method on the prototype:

function MyClass()
{}

MyClass.prototype.foo = function() { console.log('hello world!'); };


The first will create a new function object on each instantiation of your object, the second will assign a reference to a prototype method to each instance. In short: the second is more efficient, because all instances will share a single function object.

That's just the logic of a prototype chain, you can try and access anything via any object:

var objLiteral = {foo:'bar'};

When accessing objLiteral.foo JS will first look at the properties that the object itself has defined, and return the value if it is found. If JS can't find the property on the object itself, it'll check the object's prototype, hence:

objLiteral.valueOf();//method defined @Object.prototype
objLiteral.valueOf === Object.prototype.valueOf //true

But when you use your first method:

function SomeConstructor()
{
    this.methd = function()
    {
        return true;
    }
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//FALSE!

That shows that we're dealing with 2 separate function objects. Move the function definition to the prototype and f.methd === g.methd; will be true:

function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
    return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd === g.methd;//true!

In response to your comment:

Defining a method on a prototype-level allows you to change a method for a specific task, and then "reset" it back to it's default behaviour. Suppose you're in a function that's creating an AJAX request:

someObject.toString = function(){ return JSON.stringify(this);}
//when concatinating this object you'll get its json string
//do a lot of stuff
delete (someObject.toString);

Again JS will check if the object has the toString property defined on itself, which it has. So JS will delete the function you've assigned to the toString property. Next time the toString will be invoked, JS will start scanning the prototype chain all over again, and use the first occurance of the method (in the prototype). Let's clarify:

function SomeConstructor()
{
}
SomeConstructor.prototype.methd = function()
{
    return true;
}
var f = new SomeConstructor();
var g = new SomeConstructor();
f.methd = function(){return false;};
g.methd();//returns true, still <-- method is gotten from the prototype
f.methd();//returns false <-- method is defined @ instance level
delete (f.methd);
f.methd();//returns true, f doesn't have the method, but the prototype still does, so JS uses that.

Or even better, you can even replace an instance's method by a method from another prototype:

f.methd = Object.prototype.valueOf;//for as long as you need

the last example is pointless, because f has the valueOf method already: its inheritance chain looks like this: var f ---> SomeConstructor ---> Object, giving you access to all Object.prototype methods, too! Neat, isn't it?

These are just dummy examples, but I hope you see this is one of those features that make JS an incredibly flexible (sometimes too flexible, I must admit) and expressive language.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK