简体   繁体   中英

Confusion about how to create classes in JavaScript

In the past when creating "classes" in JavaScript, I have done it like this:

function Dog(name){
    this.name=name;
    this.sound = function(){
        return "Wuf";
    };
}

However, I just saw someone do it like this instead:

var Dog = (function () {
    function Dog(name) {
        this.name = name;
    }
    Dog.prototype.sound = function () {
        return "Wuf";
    };
    return Dog;
})();

Can you do it both ways, or is the way I've done it wrong? In that case, why? And what exactly is the difference between the two in terms of what we end up with? In both cases we can create an object by saying:

var fido = new Dog("Fido");
fido.sound();

I hope someone will enlighten me.

There are two important differences between your way and theirs.

  1. Wrapping in a self invoking function ( (function() { ... })(); )
  2. Using the .prototype property over this. for methods.

Wrapping things in a self invoking function, then assigning the result (as defined in the return statement to a variable is called the module pattern . It's a common pattern to ensure scope is more controlled.

Using Dog.prototype.sound = function() {} is preferable to this.sound = function() . The difference is that Dog.prototype.sound is defined once for all objects with the Dog constructor, and the this.sound = function() {} is defined again for each Dog object created .

The rule of thumb is: Things that are individual to an object (usually its properties) are to be defined on this , while things that are shared to all objects of the same type (usually functions) are to be defined on the prototype.

With your code, you're creating a new function sound for every new Dog instance that's being created. Javascript's prototype avoids this by creating only a single function which all object instances share; basically classical inheritance.

In the second code you're showing that's just additionally wrapped in an IIFE, which doesn't do much in this case.

The first is the traditional method of creating a constructor. The second an immediately invoked function expression that returns a constructor. This method allows you to keep variables within the module without leaking out into the global scope which could be an issue.

And what exactly is the difference between the two in terms of what we end up with?

They both, as you've seen, have the same result. The others have talked about prototype so I won't mention it here.

The second is preferable because it takes advantage of Javascript's prototypal inheritance mechanism.

Prototypes

Javascript inheritance is a cause of confusion, but it's actually fairly simple: every object has a prototype, which is an object that we will check when we try to access a property not on the original object. The prototype will, itself, have a prototype; in a simple case, like Dog , this will probably be Object.prototype .

In both of your examples, because of how the new operator works , we will end up with a prototype chain that looks like this: fido->Dog.prototype->Object.prototype . So, if we try to look for the name property on Fido, we'll find it right there on the object. If, on the other hand, we look for the hasOwnProperty property, we'll fail to find it on Fido, fail to find it on Dog.prototype , and then reach Object.prototype , where we'll find it.

In the case of sound , your examples define it in two different places: in the first case, fido and every other dog we create will have their own copy of the function. In the second case, Dog.prototype will have a single copy of the function, which will be accessed by individual dogs when the method is called. This avoids wasting resources on storing duplicates of the sound function.

It also means that we can extend the prototype chain; maybe we want a Corgi class that inherits the sound function from Dog . In the second case, we can simply ensure that Dog.prototype is in Corgi.prototype 's prototype chain; in the first, we would need to create an actual Dog and put it in the prototype chain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM