The difference is that the property is in the prototype chain.
Assuming we have f = new foo();
and b = new baz()
. Then we have the following situations:
Defining 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 instead assign a property to a prototype, this is:
+-----------+ +---------------+ | f | | foo.prototype | | __proto__-+---->| constructor | | | | bar | +-----------+ +---------------+
f
does not have its own bar
property, but the shared property with all other foo
instances.
Similarly for the second fragment, which is obtained 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 is mainly about structure and not wasting memory. You can add functions to an object in constructor functions:
function Foo() { this.bar = function() {}; }
but it also means that each instance of foo
has its own function, i.e. f1.bar === f2.bar
is false
, although both functions do the same.
Using a prototype gives you a clean way to separate properties common to all instances and specific instances.
In the end, it is βjustβ inheritance, which is one concept in software development (for example, aggregation) and can be used wherever it makes sense. The second fragment basically means that baz
is-a foo
, so the baz
instance, in addition to its own properties, has the same properties as the foo
instance (inherited).