Is there any difference between constructor function and prototype object when using inheritance?

前端 未结 4 1861
遥遥无期
遥遥无期 2021-01-13 00:10

Consider the following to JavaScript snippets:

function foo() {
  this.bar = function() { };
}

// or... (if we used an empty constructor function)

foo.prot         


        
相关标签:
4条回答
  • 2021-01-13 00:16

    The difference is where in the prototype chain the property is located.

    Assuming we have f = new foo(); and b = new baz(). Then we have the following situations:

    Definition of foo without using a prototype:

    +-----------+     +---------------+
    |     f     |     | foo.prototype |
    | __proto__-+---->| constructor   |  
    | bar       |     |               |
    +-----------+     +---------------+
    

    bar is a property of the object itself (f.howOwnProperty('bar') returns true).

    If you assign the property to the prototype instead, the situation is:

    +-----------+     +---------------+
    |     f     |     | foo.prototype |
    | __proto__-+---->| constructor   |  
    |           |     | bar           |
    +-----------+     +---------------+
    

    f does not have its own property bar, but the property is shared with all other foo instances.

    Similar for the second snippet, which results either in

    +-----------+     +---------------+     +---------------+
    |     b     |     | foo instance  |     | foo.prototype |
    | __proto__-+---->| __proto__    -+---->| constructor   |  
    |           |     | bar           |     |               |
    +-----------+     +---------------+     +---------------+
    

    or

    +-----------+     +---------------+     +---------------+
    |     b     |     | foo instance  |     | foo.prototype |
    | __proto__-+---->| __proto__    -+---->| constructor   |  
    |           |     |               |     | bar           |
    +-----------+     +---------------+     +---------------+
    

    Why do you want to do this?

    It's mainly about structure and not wasting memory. You can add functions to an object in a constructor function:

    function Foo() {
        this.bar = function() {};
    }
    

    but this also means that each instance of Foo has it's own function, that is, f1.bar === f2.bar is false, although both functions are doing the exact same thing.

    Using the prototype gives you a clean way to separate properties common to all instances and instance-specific ones.

    In the end, it is "just" inheritance which is one concept in software development (like aggregation) and can be used wherever it makes sense. Your second snippet basically means that a baz is-a foo, so a baz instance, in addition to its own properties, has the same properties as a foo instance (inherited).

    0 讨论(0)
  • 2021-01-13 00:28

    To add onto the existing answers:

    Making a prototype function would allow changes to it to be inherited. i.e if you write

    function foo(){}
    foo.prototype.bar = function(){return 1};
    function baz(){}
    baz.prototype = new foo();
    new baz().bar(); //returns 1
    foo.prototype.bar = function(){return 2};
    new baz().bar(); //returns 2
    

    However, putting it in the constructor would let other objects inheriting from it also "have" that function, but the function is not inherited.

    function foo(){this.bar = function(){return 1};}
    function baz(){}
    baz.prototype = new foo();
    new baz().bar(); //returns 1
    foo.prototype.bar = function(){return 2};
    new baz().bar(); //returns 1
    
    0 讨论(0)
  • 2021-01-13 00:30

    I think I'm answering the right question here, otherwise let me know.

    The difference is that using prototype results in only 1 instance.

    So, for example, baz.bar in one instance is the same as baz.bar in another. They will share values within the 'foo' instance:

    function foo() {
        var x = 0;
        this.bar = function() {};
    
        this.getVal = function() {
            return x;
        }
    
        this.setVal = function(val) {
            x = val;
        }
    }
    
    function baz() {}
    
    baz.prototype = new foo();
    
    var a = new baz(),
        b = new baz();
    
    a.setVal("1234")
    console.log(b.getVal()); // prints '1234'
    

    http://jsfiddle.net/jonathon/7GtRD/

    If a and b were directly calling 'foo', then they wouldn't be sharing the values within the foo. However, this is where it differs slightly between setting this.bar and using the prototype to create bar.

    Using the prototype would create one instance of bar. So a.bar will be the same as b.bar. If you do it the other way, they will be two different functions (doing the same thing).

    0 讨论(0)
  • 2021-01-13 00:35

    One big difference is that if you change properties of the prototype those changes will apply to all instances, including those that already exist, whereas if you change a property that was created in the constructor it will only change it for the instance you change it on.

    Regarding what some of the other answers said about setting bar in the constructor resulting in each instance having its own copy of the function: that's true if you have a function expression inside the constructor as shown in the code in the question, but not true if you assign a function reference like this:

    function myFunction() {}
    
    function foo() {
       this.bar = myFunction;
    }
    

    In that case all instances will have a bar property that refers to the same function - but an individual instance could still have its bar property assigned to something else without affecting other instances.

    0 讨论(0)
提交回复
热议问题