I recently stumbled upon the Object.create() method in JavaScript, and am trying to deduce how it is different from creating a new instance of an object with new SomeFunction(), and when you would want to use one over the other.
Consider the following example:
var test = {
val: 1,
func: function() {
return this.val;
}
};
var testA = Object.create(test);
testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2
console.log('other test');
var otherTest = function() {
this.val = 1;
this.func = function() {
return this.val;
};
};
var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1
console.log(otherTestB.val); // 2
console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2
Notice that the same behaviour is observed in both cases. It seems to me that the primary differences between these two scenarios are:
The object used in Object.create() actually forms the prototype of the new object, whereas in the new Function() from the declared properties/functions do not form the prototype.
You cannot create closures with the Object.create() syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.
Are the above statements correct? And am I missing something? When would you use one over the other?
EDIT: link to jsfiddle version of above code sample: http://jsfiddle.net/rZfYL/
Very simply said, new X is Object.create(X.prototype) with additionally running the constructor function. (And giving the constructor the chance to return the actual object that should be the result of the expression instead of this.)
That’s it. :)
The rest of the answers are just confusing, because apparently nobody else reads the definition of new either. ;)
The object used in Object.create actually forms the prototype of the new object, where as in the new Function() form the declared properties/functions do not form the prototype.
Yes, Object.create builds an object that inherits directly from the one passed as its first argument.
With constructor functions, the newly created object inherits from the constructor's prototype, e.g.:
var o = new SomeConstructor();
In the above example, o inherits directly from SomeConstructor.prototype.
There's a difference here, with Object.create you can create an object that doesn't inherit from anything, Object.create(null);, on the other hand, if you set SomeConstructor.prototype = null; the newly created object will inherit from Object.prototype.
You cannot create closures with the Object.create syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.
Well, you can create closures, e.g. using property descriptors argument:
var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});
o.foo; // "foobar"
Note that I'm talking about the ECMAScript 5th Edition Object.create method, not the Crockford's shim.
The method is starting to be natively implemented on latest browsers, check this compatibility table.
Here are the steps that happen internally for both calls:
(Hint: the only difference is in step 3)
new Test():
create new Object() obj
set obj.__proto__ to Test.prototype
return Test.call(obj) || obj;
// normally obj is returned but constructors in JS can return a value
Object.create( Test.prototype )
create new Object() obj
set obj.__proto__ to Test.prototype
return obj;
So basically Object.create doesn't execute the constructor.
Let me try to explain (more on Blog) :
When you write Car constructor var Car = function(){}, this is how things are internally:
We have one {prototype} hidden link to Function.prototype which is not accessible and one prototype link to Car.prototype which is accessible and has an actual constructor of Car. Both Function.prototype and Car.prototype have hidden links to Object.prototype.
When we want to create two equivalent objects by using the new operator and create method then we have to do it like this: Honda = new Car(); and Maruti = Object.create(Car.prototype).
What is happening?
Honda = new Car(); — When you create an object like this then hidden {prototype} property is pointed to Car.prototype. So here, the {prototype} of the Honda object will always be Car.prototype — we don't have any option to change the {prototype} property of the object. What if I want to change the prototype of our newly created object?
Maruti = Object.create(Car.prototype) — When you create an object like this you have an extra option to choose your object's {prototype} property. If you want Car.prototype as the {prototype} then pass it as a parameter in the function. If you don't want any {prototype} for your object then you can pass null like this: Maruti = Object.create(null).
Conclusion — By using the method Object.create you have the freedom to choose your object {prototype} property. In new Car();, you don't have that freedom.
Preferred way in OO JavaScript :
Suppose we have two objects a and b.
var a = new Object();
var b = new Object();
Now, suppose a has some methods which b also wants to access. For that, we require object inheritance (a should be the prototype of b only if we want access to those methods). If we check the prototypes of a and b then we will find out that they share the prototype Object.prototype.
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
Problem — we want object a as the prototype of b, but here we created object b with the prototype Object.prototype.
Solution — ECMAScript 5 introduced Object.create(), to achieve such inheritance easily. If we create object b like this:
var b = Object.create(a);
then,
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
So, if you are doing object oriented scripting then Object.create() is very useful for inheritance.
This:
var foo = new Foo();
and
var foo = Object.create(Foo.prototype);
are quite similar. One important difference is that new Foo actually runs constructor code, whereas Object.create will not execute code such as
function Foo() {
alert("This constructor does not run with Object.create");
}
Note that if you use the two-parameter version of Object.create() then you can do much more powerful things.
The difference is the so-called "pseudoclassical vs. prototypal inheritance". The suggestion is to use only one type in your code, not mixing the two.
In pseudoclassical inheritance (with "new" operator), imagine that you first define a pseudo-class, and then create objects from that class. For example, define a pseudo-class "Person", and then create "Alice" and "Bob" from "Person".
In prototypal inheritance (using Object.create), you directly create a specific person "Alice", and then create another person "Bob" using "Alice" as a prototype. There is no "class" here; all are objects.
Internally, JavaScript uses "prototypal inheritance"; the "pseudoclassical" way is just some sugar.
See this link for a comparison of the two ways.
function Test(){
this.prop1 = 'prop1';
this.prop2 = 'prop2';
this.func1 = function(){
return this.prop1 + this.prop2;
}
};
Test.prototype.protoProp1 = 'protoProp1';
Test.prototype.protoProp2 = 'protoProp2';
var newKeywordTest = new Test();
var objectCreateTest = Object.create(Test.prototype);
/* Object.create */
console.log(objectCreateTest.prop1); // undefined
console.log(objectCreateTest.protoProp1); // protoProp1
console.log(objectCreateTest.__proto__.protoProp1); // protoProp1
/* new */
console.log(newKeywordTest.prop1); // prop1
console.log(newKeywordTest.__proto__.protoProp1); // protoProp1
Summary:
1) with new keyword there are two things to note;
a) function is used as a constructor
b) function.prototype object is passed to the __proto__ property ... or where __proto__ is not supported, it is the second place where the new object looks to find properties
2) with Object.create(obj.prototype) you are constructing an object (obj.prototype) and passing it to the intended object ..with the difference that now new object's __proto__ is also pointing to obj.prototype (please ref ans by xj9 for that)
Object creation variants.
Variant 1 : 'new Object()' -> Object constructor without arguments.
var p1 = new Object(); // 'new Object()' create and return empty object -> {}
var p2 = new Object(); // 'new Object()' create and return empty object -> {}
console.log(p1); // empty object -> {}
console.log(p2); // empty object -> {}
// p1 and p2 are pointers to different objects
console.log(p1 === p2); // false
console.log(p1.prototype); // undefined
// empty object which is in fact Object.prototype
console.log(p1.__proto__); // {}
// empty object to which p1.__proto__ points
console.log(Object.prototype); // {}
console.log(p1.__proto__ === Object.prototype); // true
// null, which is in fact Object.prototype.__proto__
console.log(p1.__proto__.__proto__); // null
console.log(Object.prototype.__proto__); // null
Variant 2 : 'new Object(person)' -> Object constructor with argument.
const person = {
name: 'no name',
lastName: 'no lastName',
age: -1
}
// 'new Object(person)' return 'person', which is pointer to the object ->
// -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p1 = new Object(person);
// 'new Object(person)' return 'person', which is pointer to the object ->
// -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p2 = new Object(person);
// person, p1 and p2 are pointers to the same object
console.log(p1 === p2); // true
console.log(p1 === person); // true
console.log(p2 === person); // true
p1.name = 'John'; // change 'name' by 'p1'
p2.lastName = 'Doe'; // change 'lastName' by 'p2'
person.age = 25; // change 'age' by 'person'
// when print 'p1', 'p2' and 'person', it's the same result,
// because the object they points is the same
console.log(p1); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(p2); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(person); // { name: 'John', lastName: 'Doe', age: 25 }
Variant 3.1 : 'Object.create(person)'. Use Object.create with simple object 'person'. 'Object.create(person)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'person'.
const person = {
name: 'no name',
lastName: 'no lastName',
age: -1,
getInfo: function getName() {
return `${this.name} ${this.lastName}, ${this.age}!`;
}
}
var p1 = Object.create(person);
var p2 = Object.create(person);
// 'p1.__proto__' and 'p2.__proto__' points to
// the same object -> 'person'
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(p1.__proto__);
console.log(p2.__proto__);
console.log(p1.__proto__ === p2.__proto__); // true
console.log(person.__proto__); // {}(which is the Object.prototype)
// 'person', 'p1' and 'p2' are different
console.log(p1 === person); // false
console.log(p1 === p2); // false
console.log(p2 === person); // false
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);
console.log(p1); // empty object - {}
console.log(p2); // empty object - {}
// add properties to object 'p1'
// (properties with the same names like in object 'person')
p1.name = 'John';
p1.lastName = 'Doe';
p1.age = 25;
// add properties to object 'p2'
// (properties with the same names like in object 'person')
p2.name = 'Tom';
p2.lastName = 'Harrison';
p2.age = 38;
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);
// { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);
// { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);
// use by '__proto__'(link from 'p1' to 'person'),
// person's function 'getInfo'
console.log(p1.getInfo()); // John Doe, 25!
// use by '__proto__'(link from 'p2' to 'person'),
// person's function 'getInfo'
console.log(p2.getInfo()); // Tom Harrison, 38!
Variant 3.2 : 'Object.create(Object.prototype)'. Use Object.create with built-in object -> 'Object.prototype'. 'Object.create(Object.prototype)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'Object.prototype'.
// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p1' property '__proto__', which is link to 'Object.prototype'
var p1 = Object.create(Object.prototype);
// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p2' property '__proto__', which is link to 'Object.prototype'
var p2 = Object.create(Object.prototype);
console.log(p1); // {}
console.log(p2); // {}
console.log(p1 === p2); // false
console.log(p1.prototype); // undefined
console.log(p2.prototype); // undefined
console.log(p1.__proto__ === Object.prototype); // true
console.log(p2.__proto__ === Object.prototype); // true
Variant 4 : 'new SomeFunction()'
// 'this' in constructor-function 'Person'
// represents a new instace,
// that will be created by 'new Person(...)'
// and returned implicitly
function Person(name, lastName, age) {
this.name = name;
this.lastName = lastName;
this.age = age;
//-----------------------------------------------------------------
// !--- only for demonstration ---
// if add function 'getInfo' into
// constructor-function 'Person',
// then all instances will have a copy of the function 'getInfo'!
//
// this.getInfo: function getInfo() {
// return this.name + " " + this.lastName + ", " + this.age + "!";
// }
//-----------------------------------------------------------------
}
// 'Person.prototype' is an empty object
// (before add function 'getInfo')
console.log(Person.prototype); // Person {}
// With 'getInfo' added to 'Person.prototype',
// instances by their properties '__proto__',
// will have access to the function 'getInfo'.
// With this approach, instances not need
// a copy of the function 'getInfo' for every instance.
Person.prototype.getInfo = function getInfo() {
return this.name + " " + this.lastName + ", " + this.age + "!";
}
// after function 'getInfo' is added to 'Person.prototype'
console.log(Person.prototype); // Person { getInfo: [Function: getInfo] }
// create instance 'p1'
var p1 = new Person('John', 'Doe', 25);
// create instance 'p2'
var p2 = new Person('Tom', 'Harrison', 38);
// Person { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);
// Person { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);
// 'p1.__proto__' points to 'Person.prototype'
console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] }
// 'p2.__proto__' points to 'Person.prototype'
console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] }
console.log(p1.__proto__ === p2.__proto__); // true
// 'p1' and 'p2' points to different objects(instaces of 'Person')
console.log(p1 === p2); // false
// 'p1' by its property '__proto__' reaches 'Person.prototype.getInfo'
// and use 'getInfo' with 'p1'-instance's data
console.log(p1.getInfo()); // John Doe, 25!
// 'p2' by its property '__proto__' reaches 'Person.prototype.getInfo'
// and use 'getInfo' with 'p2'-instance's data
console.log(p2.getInfo()); // Tom Harrison, 38!
Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
Internally Object.create does this:
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
The syntax just takes away the illusion that JavaScript uses Classical Inheritance.
Object.create(Constructor.prototype) is the part of new Constructor
this is new Constructor implementation
// 1. define constructor function
function myConstructor(name, age) {
this.name = name;
this.age = age;
}
myConstructor.prototype.greet = function(){
console.log(this.name, this.age)
};
// 2. new operator implementation
let newOperatorWithConstructor = function(name, age) {
const newInstance = new Object(); // empty object
Object.setPrototypeOf(newInstance, myConstructor.prototype); // set prototype
const bindedConstructor = myConstructor.bind(newInstance); // this binding
bindedConstructor(name, age); // execute binded constructor function
return newInstance; // return instance
};
// 3. produce new instance
const instance = new myConstructor("jun", 28);
const instance2 = newOperatorWithConstructor("jun", 28);
console.log(instance);
console.log(instance2);
new Constructor implementation contains Object.create method
newOperatorWithConstructor = function(name, age) {
const newInstance = Object.create(myConstructor.prototype); // empty object, prototype chaining
const bindedConstructor = myConstructor.bind(newInstance); // this binding
bindedConstructor(name, age); // execute binded constructor function
return newInstance; // return instance
};
console.log(newOperatorWithConstructor("jun", 28));
Related
What is the difference between these two codes?
let user = new function() {
this.name = "John";
this.isAdmin = false;
}
vs
let user = {
name: "John",
isAdmin: false
}
The only difference is that the first user, created via new, has an internal prototype of a (nearly) empty object, and that empty object inherits from Object.prototype:
instance <- (empty object) <- Object.prototype
let user = new function() {
this.name = "John";
this.isAdmin = false;
};
console.log(user);
Technically, the object isn't entirely empty, it has a non-enumerable constructor property pointing to the function
This nearly empty object is the .prototype property of the function - but since that prototype object doesn't have any properties on it, it looks empty. If you had put properties on the function's .prototype object, these would be visible on the intermediate object:
function Foo() {
this.name = "John";
this.isAdmin = false;
}
Foo.prototype.prop = 'val';
let user = new Foo();
console.log(user);
console.log(Object.getPrototypeOf(user).hasOwnProperty('prop'));
console.log(Object.getPrototypeOf(user) === Foo.prototype);
The user from an object literal, on the other hand, inherits directly from Object.prototype:
instance <- Object.prototype
let user = {
name: "John",
isAdmin: false
}
console.log(Object.getPrototypeOf(user) === Object.prototype);
Firstly both of them create a new object and the following code inside them is assigned to the object.
They then execute the code in the function body and can return the value.
Here is my code:
var Person = new Function() // same as function Person(){}
var john = new Person()
now I have prototype chain like that: Object -> Function -> Person -> john
Now I am doing something like that:
Function.prototype.bar = "boo"
So I expect to have Person.bar and john.bar to be "boo"
Person.bar // boo
john.bar // undefined
so what happened? I dived into and found out that john.__proto__ is prototype of Person, but john.__proto__.__proto__ is NOT prototype of Function, it's prototype of Object, so I lost one piece of chain(Finction). that's why john.bar was undefined. So why is this happening? shouldn't I be able to access Function prototype properties from john?
When you have
var Person = new Function()
you get an empty function which does nothing and returns nothing, eg
function Person() {
}
When you create an instance of Person with new, the newly created object will look at Person.prototype, and since Person.prototype inherits from Object (not Function), you won't see the .bar property.
function Person() {
}
const john = new Person();
console.log(
Object.getPrototypeOf(john) === Person.prototype,
Object.getPrototypeOf(Person.prototype) === Object.prototype
);
It's really weird to try to create an instance of a function, but if you wanted to, I suppose you could get what you're looking for by having Person return a Function instance:
Function.prototype.bar = "boo"
function Person() {
return new Function();
};
const john = new Person();
console.log(john.bar);
I'd highly recommend not trying to create Function instances like this, though.
If you want an (odd) inheritance chain of
Object -> Function -> Person -> john
then you can use Object.create:
//const Person = Object.create(Function);
// or
const Person = new Function();
const john = Object.create(Person);
Function.prototype.foo = 'foo';
console.log(john.foo);
Consider the following image taken from this answer.
As you can see, when you create a function in JavaScript a new prototype object is automatically created as well.
function Person() {}
Hence, the above code is actually:
function Person() {}
Person.prototype = { constructor: Person };
Now, you should also understand that the __proto__ property of a function is different from its prototype property.
function Person() {}
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true
When you create an instance of Person using the new keyword, that instance object inherits from Person.prototype and not from Person or Person.__proto__:
function Person() {}
const john = new Person;
console.log(john.__proto__ !== Person); // true
console.log(john.__proto__ !== Person.__proto__); // true
console.log(john.__proto__ === Person.prototype); // true
The same goes for functions created by calling new Function.
const Person = new Function;
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true
That's the reason why john does not inherit from Function.prototype. The prototype chain for john is as follows.
__proto__ __proto__ __proto__
john -----------> Person.prototype -----------> Object.prototype -----------> null
Whereas the prototype chain of Person is as follows:
__proto__ __proto__ __proto__
Person -----------> Function.prototype -----------> Object.prototype -----------> null
Here's the proof:
const Person = new Function;
const john = new Person;
console.log(john.__proto__ === Person.prototype); // true
console.log(john.__proto__.__proto__ === Object.prototype); // true
console.log(john.__proto__.__proto__.__proto__ === null); // true
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.__proto__.__proto__ === Object.prototype); // true
console.log(Person.__proto__.__proto__.__proto__ === null); // true
This is because Person.prototype !== Person.__proto__.
Now, you may ask why do we have both the prototype and the __proto__ properties. The reason for this is because an object in JavaScript (let's call it derived) inherits from another object (let's call it base) if and only if derived.__proto__ = base. Consider the following code:
const base = { foo: 10 };
const derived = {};
derived.__proto__ = base; // derived now inherits from base
console.log(derived.foo); // 10
const newBase = { bar: 20 };
derived.__proto__ = newBase; // derived no longer inherits from base, it inherits from newBase
console.log(derived.foo); // undefined
console.log(derived.bar); // 20
Now, when you create an instance of a function the instance actually inherits from the prototype of the function. It doesn't inherit from the function.
function Person() {}
const john = new Person;
The above code is equivalent to:
function Person() {}
Person.prototype = { constructor: Person };
const john = { __proto__: Person.prototype };
Person.call(john);
Hope that clears things.
When I read the CHAPTER 6 OBJECT-ORIENTED PROGRAMMING of Professional JavaScript for Web Developers, It shows a pattern for create object by constructor.
// implicit way
function Person(name) {
this.name = name;
}
var person1 = new Person('Greg')
person1 instanceof Person
To create a new instance of Person, use the new operator. Calling a constructor in this manner essentially causes the following four steps to be taken:
Create a new object.
Assign the this value of the constructor to the new object (so this points to the new object).
Execute the code inside the constructor (adds properties to the new object).
Return the new object.
That show the implicit way how an object instance be created.
And I want to follow it explicitly. Something like:
function Person(name) {
var o = Object.call(this) // step 1 and step 2
o.name = name // step 3
return o // step 4
}
var person1 = new Person('Greg')
person1 instanceof Person // false
In fact, It can't work as the constructor pattern. Why? And how can I modify my code to create a constructor with the explicit way?
https://javascript.info/constructor-new
Because Object.call(this) makes little sense, as that function does not care of its context and returns a plain object. Instead you can use:
Object.create(this.constructor.prototype)
The book quoted leaves out a seriously important detail of what new does:
1 Create a new object.
really means
1.1 Create a new object,
1.2 which has been prototyped on the constructor function's prototype property.
Hence the results of:
function Person(name) {
var o = Object.create( Person.prototype);
o.name = name // step 3
return o // step 4
}
var person1 = new Person('Greg')
console.log( person1 instanceof Person); // true
console.log( person1.constructor) // Person
Not that you would do this in real code, but for learning purposes it's an interesting demonstration.
The constructor property
Generally an object inherits its "constructor" property from its inheritance chain, searching backwards from the object's __proto property.
You could create a local own-property of an object called "constructor" which would then shadow the inherited value (and which would also be enumerable by default).
If you set the constructor property of a function's prototype property, its value changes without the property becoming enumerable in the process:
function F() {}
console.log (F.prototype.hasOwnProperty("constructor")); // true
let f = new F();
console.log( f.constructor.name); // F
F.prototype.constructor = Object;
let g = new F();
console.log( g.constructor.name); // Object
F.prototype.foo = "bar";
for( var prop in F.prototype) {
console.log( "F.prototype.%s = %s", prop, F.prototype[ prop]); // foo only
}
In JavaScript, if I create a constructor function Foo, a prototype
object will also be created as Foo.prototype. So I tried this:
function Foo() { this.xx = 1000}
I thought the created prototype object Foo.prototype will have the
property xx = 1000. So I tried this:
console.log(Foo.prototype.xx);
But the result is "undefined". Why is this?
Shouldn't there be a Foo.prototype object with single property xx
to be 1000?
Thanks.
If you add the property inside the constructor, each instance will have an own copy:
function Foo1() {
this.xx = [1000];
}
var foo1 = new Foo1(),
foo2 = new Foo1();
foo1.hasOwnProperty('xx'); // true
foo2.hasOwnProperty('xx'); // true
foo1.xx == foo2.xx; // false (each instance has a different copy)
You can also use prototypical inheritance. Then, a the same inherited property is shared among all the instances:
function Foo2() {}
var foo1 = new Foo2(),
foo2 = new Foo2();
'xx' in foo1; // false
'xx' in foo2; // false
Foo2.prototype.xx = [1000];
'xx' in foo1; // true
'xx' in foo2; // true
foo1.hasOwnProperty('xx'); // false (it's inherited)
foo2.hasOwnProperty('xx'); // false (it's inherited)
foo1.xx == foo2.xx; // true (all instances share the same value)
I am working on implementing a simple Class in JavaScript. I know there are many great libraries out there that already does this. However, my intent is to understand the JavaScript prototype model better. Anyhow, I wrote the following. It is working as far as I can tell but with one catch I will describe later:
function Class(constructor,prototypeObj){
var c = constructor;
c.create = function(){
//var o = new constructor();
var o = Object.create(c.prototype);
c.apply(o,arguments);
return o;
};
c.prototype = prototypeObj;
return c;
}
var Animal = Class(
function Animal(life){
this.life = life;
},
{
type: "animal",
sayLife: function(){
console.log(this.life);
}
}
);
var o = Animal.create(15);
console.log(o instanceof Animal); // True
console.log(o.sayLife()); // 15
console.log(o.type); // "animal"
However, my problem is that when I input in o (for the instance) in the console; it prints
Object {life: 15, type: "animal", sayLife: function}life: 15 __proto__: Object
But I would like it to be
Animal {life: 15, type: "animal", sayLife: function}life: 15 __proto__: Object
If I change line 4 and 5 in the constructor.create method to use new constructor() instead of Object.create(constructor.prototype), I get the desired behaviour but then I have issues passing in arguments to the constructor when initializing a new object. If I return a function other than the constructor passed into the class function, then the objects names would not be Animal but something else like "Object" or "F".
So my question is is there any way to implement the Class function such that the instances of the Class always share the same name as the constructor function?
function Class(constructor, prototypeObj) {
var c = constructor;
c.create = function() {
//var o = new constructor();
var o = Object.create(c.prototype);
c.apply(o, arguments);
return o;
};
c.prototype = prototypeObj;
c.prototype.constructor = constructor;
return c;
}
var Animal = Class(
function Animal(life) {
this.life = life;
}, {
type: "animal",
sayLife: function() {
console.log(this.life);
}
}
);
var o = Animal.create(15);
console.log(o);
If you simply want to change the type of the Object being printed in the console, then you need to adjust the constructor function's prototype property's constructor property, like this
c.prototype = prototypeObj;
c.prototype.constructor = constructor;
return c;
Did you know that the constructor function is not really a special function? It's just like any other method on the prototype. So you don't need to treat it any differently from other prototype methods. This is what I usually do:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
This allows me to create constructors as follows:
var Animal = defclass({
constructor: function Animal(life) { // note that I named the constructor
this.life = life;
},
sayLife: function () {
console.log(this.life);
},
type: "animal"
});
Then we can use it as follows:
var o = new Animal(15);
console.log(o instanceof Animal); // true
console.log(o.sayLife()); // 15
console.log(o.type); // "animal"
The reason your code didn't work as expected was because you forgot to reset the constructor property on the prototype. However using my method, since the constructor method is already a property of prototype, you don't have to do anything else.
For more information about prototypal inheritance see the following question:
JavaScript inheritance and the constructor property
You might want to use Object.create()
The Object.create() method creates a new object with the specified prototype object and properties.
This allows you to fully configure an object when creating, including the possibility of specifiying any constructor:
var o = Object.create(Animal.prototype,{
constructor:{
value: Animal
}
})
Edit:
See #dfsq 's answer and the comments below for an even simpler solution.