Reputation: 5018
I have two functions to initialise objects. init and differentInit.
function init(){
return {a:5};
}
function differentInit(){
this.a =5;
}
obj = init();
newobj = new differentInit()
how are the objects obj and newobj different?
This is what the JavaScript interpreter shows as the contents of the two objects.
>obj
<·Object {a: 5}
>newobj
<·differentInit {a: 5}
EDIT: As the answers (which are really good) have pointed out that newobj
has an additional prototype as differentInit.prototype
. I had thought an object can only be created with an additional prototype using the Object.create()
method. I don't know if this a far too generic question, but how many other ways are there to create objects with prototypes? And can the method used in this question be considered a good way to create an object with prototypes?
Upvotes: 5
Views: 151
Reputation: 1074355
how are the objects obj and newobj different?
Given the functions you've shown, the only real difference is that the second one has an extra prototype (with a different constructor
property) between it and Object.prototype
. The first one directly inherits from Object.prototype
:
E.g., obj
:
+----------+ Object.prototype-------------+--->| toString | | | valueOf | | | ... | | +----------+ +---------------+ | obj---->| [[Prototype]] |----+ | a: 5 | +---------------+
vs. newObj
:
+----------+ Object.prototype--------------------------------------+--->| toString | | | valueOf | | | ... | | +----------+ +---------------+ | differentInit.prototype------+--->| [[Prototype]] |---+ | +---------------+ | | +---------------+ | newObj->| [[Prototype]] |----+ | a: 5 | +---------------+
(Note that as Oriol points out, the objects that Object.prototype
and differentInit.prototype
point to both have a constructor
property that points to Object
and differentInit
respectively. So obj.constructor
will be Object
and newObj.constructor
will be differentInit
. I'd've added it to the diagrams, but it complicates them unnecessarily...)
Unless you add something to differentInit.prototype
, it doesn't make any significant practical difference.
Since you've tagged your question json
, I'll just note that there's no JSON being used anywhere in your question. JSON is a textual notation for data exchange. If you're dealing with program source code, and not dealing with a string, you're not dealing with JSON.
I always thought an object can only be created with a prototype using the
Object.create()
method.
In JavaScript, all objects have prototypes unless they're created with Object.create(null)
(which gives them null
in their [[Prototype]]
internal slot, e.g., they have no prototype).
...how many other ways are there to create objects with prototypes?
You can create objects with prototypes by:
Using an object initializer, e.g. obj = {}
, which creates it using Object.prototype
as its prototype.
By using the new
operator with a function; the object that the function's prototype
property refers to is assigned as the prototype of the object that new
creates. All functions created with the function
(or class
) keyword get a prototype
property with a blank object on it; that can then be added to, or replaced. (If the function's prototype
is null
, new
uses Object.prototype
instead.)
Note that the function you use with new
can either be any function defined using the function
keyword:
// Using `function`
function Foo() {
}
Foo.prototype.bar = function() {
console.log("Foo instance says 'bar'!");
};
var f = new Foo();
f.bar();
or as of ES2015, a function defined with the class
keyword:
class Foo {
bar() {
console.log("Foo instance says 'bar'!");
}
}
var f = new Foo();
f.bar();
Barring a couple of minor details, the two snippets above do the same thing: They define a function called Foo
, which you are expected to call via new
, which has Foo.prototype
with bar
on it.
Using Object.create(p)
, where p
is assigned as the resulting object's prototype. Unlike #2 above, p
can be null
to create an object that doesn't have a prototype. This was added in ES5, although it can be shimmed (other than the null
bit). (There's an optional second argument that can't be shimmed.)
You can set an object's prototype after creation in two ways:
Using Reflect.setPrototypeOf(target, proto)
or the very similar Object.setPrototypeOf(target, proto)
, which are new in ES2015. (The only difference between them is that Reflect.setPrototypeOf
will throw if you pass it a non-object as target
; Object.setPrototypeOf
will just return what you gave it unchanged in that case. That, and some JavaScript engines don't have the Reflect
object yet, but will soon.)
(Backward compat only) Using the __proto__
property, provided that the object inherits (directly or indirectly) from Object.prototype
. Notes:
A. This is specified for JavaScript engines in web browsers only.
B. It was not part of the specification before ES2015.
C. Since it wasn't in the spec until ES2015, is only defined on web browsers, and will fail if the object doesn't inherit from Object.prototype
, in the very rare case you need to dynamically set an object's prototype after creating it, use Reflect.setPrototypeOf
instead.
And can the method used in this question be considered a good way to create an object with prototypes?
If by "the method" you mean new differentInit
, yes, that's a completely normal way to create an object with a specific prototype. Typically you use that form when you're going to create several objects (a "class" of objects in the general sense of the word; e.g., objects that have a majority of traits in common). It's also perfectly normal and fine to use Object.create
for that use case (some people don't like to use the new
operator at all). If you're just doing a one-off where you want a specific object to inherit from another specific object, Object.create
is the way to go.
Upvotes: 9
Reputation: 288130
The most practical differences are
obj.constructor === Object
newobj.constructor === differentInit
Object.getPrototypeOf(obj) === Object.prototype;
Object.getPrototypeOf(newobj) === differentInit.prototype;
obj instanceof differentInit === false
newobj instanceof differentInit === true
Otherwise (unless you modify differentInit.prototype
), they are basically the same.
Upvotes: 4