Confused about Douglas Crockford's object function - javascript

I know Crockford has a famous object function for inheritance in JavaScript:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
But I am confused, after the line F.prototype = o, why he doesn't he reset the F.prototype's constructor, like this:
F.prototype.constructor = F
Isn't that common practice?

Isn't that common practice?
Only when your're creating subclasses (constructor functions with prototypes inheriting from other prototypes).
But that's not the purpose of this code, which basically Object.create. It takes the part of creating the object which inherits from another object, nothing else. The F constructor function is only intermediate and not supposed to be exposed.
F.prototype = o;
why he doesn't he do F.prototype.constructor = F?
Because that would change o itself. The aim is only to create a new object. Notice that it returns an instance of the intermediate constructor, not the constructor itself.
Where would the constructor be set (if needed)? On the new object that is instantiated by object:
function inherit(chd, par) {
chd.prototype = object(par.prototype);
chd.prototype.constructor = chd;
}
function Foo() {}
function Bar() {}
inherit(Foo, Bar);
/* Because of overwriting `constructor`: */
Foo.prototype.constructor === Foo
(new Foo).constructor === Foo
/* Because of the prototype chain: */
new Foo instanceof Bar // true, because
Foo.prototype instanceof Bar // true

Since you are using an instance of F as prototype object itself, there is no benefit in setting the constructor property.
For example:
function Foo() {}
function Bar() {}
Bar.prototype = object(Foo.prototype);
Bar.prototype.constructor = Bar;
So now Bar.prototype is an instance of F. We assigned the constructor property to that instance which would shadow the constructor property assigned to F.prototype. So why bother assigning it in the first place?
Generally speaking the constructor property has no significance in JavaScript, but it may be useful in your own code. I.e. your code might depend on the correct value of constructor. But in the object function, F is just a temporary constructor and object just replicates the functionality of Object.create, which is supported in newer browsers. I cannot think of a use case where you want a reference to F in your code.

Related

javascript prototypical inheritance confused

given the standard way of achieving inheritance like this
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
why is necesary to do
SubClass.prototype = Object.create(BaseClass.prototype);
and end up with something like
function F(){}
F.prototype = BaseClass.prototype;
SubClass.prototype = new F();
instead of just doing
Subclass.prototype = BaseClass.prototype;
Assigning values to things in JavaScript really just copies a reference (unless working with primitive types). So when you do this:
Subclass.prototype = BaseClass.prototype;
What you're really doing is assigning the prototype of SubClass to the same location in memory as the prototype of BaseClass, therefore any prototype related changes you make to SubClass will also affect BaseClass. Here's a little example:
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = BaseClass.prototype;
SubClass.prototype.constructor = SubClass;
SubClass.prototype.subClassFunction = function(){
console.log("Added this to SubClass");
}
var baseObj = new BaseClass();
baseObj.subClassFunction(); // => "Added this to SubClass"
That's why you want to use
SubClass.prototype = Object.create(BaseClass.prototype);
because it will create a new and unique object with the specified prototype instead.
You can read more about how this function works here.
Object Reference!
Say BaseClass has a method toString:
BaseClass.prototype.toString = function() {
return 'foo'
}
But you redefine the toString method in SubClass:
SubClass.prototype.toString = function() {
return 'bar'
}
You'll expect:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'foo'
s.toString() //=> 'bar'
But if you use assignment to create inheritance what you will get is:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'bar'
s.toString() //=> 'bar'
Because BaseClass.prototype and SubClass.prototype now reference the same object
Inheritance, the __proto__ :
When an object SubClass inherits from another object BaseClass, in JavaScript that means that there is a special property SubClass.__proto__ = BaseClass.
Code :
function BaseClass() {
}
function SubClass() {
}
var BaseClass = new BaseClass();
var SubClass = new SubClass();
BaseClass.a = 5;
SubClass.b = 10;
SubClass.__proto__ = BaseClass;
console.log(SubClass);
Output :
Here, BaseClass is inherited by SubClass and BaseClass variable is accessable through the SubClass.
The syntax of JavaScript can be somewhat confusing. In JS, there isn't class inheritance but instance-based inheritance. An instance's parent is also called its prototype.
When you write instance.something or instance['something'], the JS engine looks at the instance to see if it has a member called something. If it doesn't, then it looks at the instance's prototype. If that object doesn't have the member something, it looks at the prototype's prototype, again and again until it finds the property or reaches an instance which inherits from null. In that case it will simply return undefined.
Functions have a special property called prototype which is something else. The function's .prototype is a simple object that has a constructor property which refers back to the function itself. When you create an object with the new keyword, that object's prototype will be set to the function's .prototype property. This is where the confusion comes from: the .prototype property of a constructor can be seen as the default prototype of all instances made with said constructor.
So when you add methods to a class by writing something like this:
MyClass.prototype.foo = function() {
alert('foo');
};
...you're actually storing the function in the prototype of all MyClass instances. When the JS engine looks at the instances of MyClass, it will look for the foo member which it won't find. Then it will look at the instance's prototype which happens to be set to MyClass.prototype and it will find the foo member and fetch it.
It's important to make the difference between an instance's prototype and a function's .prototype, but most people don't realize it. When they speak of a class's prototype, they're talking about MyClass.prototype. The instance prototype is accessible via __proto__ in many browsers, but that's not a standard feature of JavaScript and shouldn't be used in your code.
Now let's look at the code you're using to simulate class inheritance.
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
Object.create(parent) can be seen as a function that does this:
return {
__proto__ : parent
};
In other words, it creates a blank Object whose prototype is the passed object. Since all SubClass instances will inherit from Subclass.prototype, replacing SubClass.prototype with an object that inherits from BaseClass.prototype makes sure all SubClass instances also inherit from BaseClass.
However, as I said earlier, the default .prototype attribute of a function is an empty object whose .constructor is set to the function itself. So by manually setting the .constructor again, we're perfectly mimicking default prototype behavior. If we don't do that, then instance.constructor will return the first defined .constructor property down the prototype chain, which will be BaseClass. It doesn't really change anything in terms of behavior unless our code actually depends on the constructor property, but it's safer to have it.
As a final note, like others mentioned before I could finally post this answer, you can't just do SubClass.prototype = BaseClass.prototype; because then you wouldn't be able to add methods to the SubClass without adding them to the BaseClass.

I have modified the constructor of a JavaScript what that does imply? [duplicate]

Consider the following code.
function a() {}
function b() {}
function c() {}
b.prototype = new a();
c.prototype = new b();
console.log((new a()).constructor); //a()
console.log((new b()).constructor); //a()
console.log((new c()).constructor); //a()
Why isn't the constructor updated for b and c?
Am I doing inheritance wrong?
What is the best way to update the constructor?
Further, please consider the following.
console.log(new a() instanceof a); //true
console.log(new b() instanceof b); //true
console.log(new c() instanceof c); //true
Given that (new c()).constructor is equal to a() and Object.getPrototypeOf(new c()) is a{ }, how is it possible for instanceof to know that new c() is an instance of c?
http://jsfiddle.net/ezZr5/
Okay, let's play a little mind game:
From the above image we can see:
When we create a function like function Foo() {}, JavaScript creates a Function instance.
Every Function instance (the constructor function) has a property prototype which is a pointer.
The prototype property of the constructor function points to its prototype object.
The prototype object has a property constructor which is also a pointer.
The constructor property of the prototype object points back to its constructor function.
When we create a new instance of Foo like new Foo(), JavaScript creates a new object.
The internal [[proto]] property of the instance points to the prototype of the constructor.
Now, the question arises that why doesn't JavaScript attach the constructor property to the instance object instead of the prototype. Consider:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function () {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
As you can see the constructor property is just another method of the prototype, like area in the example above. What makes the constructor property special is that it's used to initialize an instance of the prototype. Otherwise it's exactly the same as any other method of the prototype.
Defining the constructor property on the prototype is advantageous for the following reasons:
It's logically correct. For example consider Object.prototype. The constructor property of Object.prototype points to Object. If the constructor property was defined on the instance then Object.prototype.constructor would be undefined because Object.prototype is an instance of null.
It's treated no differently from other prototype methods. This makes the job of new easier since it doesn't need to define the constructor property on every instance.
Every instance shares the same constructor property. Hence it's efficient.
Now when we talk about inheritance, we have the following scenario:
From the above image we can see:
The derived constructor's prototype property is set to the instance of the base constructor.
Hence the internal [[proto]] property of the instance of the derived constructor points to it too.
Thus the constructor property of the derived constructor instance now points to the base constructor.
As for the instanceof operator, contrary to popular belief it doesn't depend on the constructor property of the instance. As we can see from above, that would lead to erroneous results.
The instanceof operator is a binary operator (it has two operands). It operates on an instance object and a constructor function. As explain on Mozilla Developer Network, it simply does the following:
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
To put it simply if Foo inherits from Bar, then the prototype chain for the instance of Foo would be:
foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
As you can see, every object inherits from the Object constructor. The prototype chain ends when an internal [[proto]] property points to null.
The instanceof function simply traverses the prototype chain of the instance object (the first operand) and compares the internal [[proto]] property of each object to the prototype property of the constructor function (the second operand). If they match, it returns true; and else if the prototype chain ends, it returns false.
By default,
function b() {}
then b.prototype has a .constructor property which is set to b automatically. However, you're currently overwriting the prototype and thus discarding that variable:
b.prototype = new a;
Then b.prototype does not have a .constructor property anymore; it was erased with the overwrite. It does inherit from a though, and (new a).constructor === a, and hence (new b).constructor === a (it is referring to the same property in the prototype chain).
Best to do is to simply setting it manually afterwards:
b.prototype.constructor = b;
You could also make a little function for this:
function inherit(what, from) {
what.prototype = new from;
what.prototype.constructor = what;
}
http://jsfiddle.net/79xTg/5/
constructor is a regular, non-enumerable property of the default value of the prototype property of function objects. Thus, assigning to prototype will lose the property.
instanceof will still work as it does not use constructor, but rather scans the prototype chain of the object for the (current) value of the function's prototype property, ie foo instanceof Foo is equivalent to
var proto = Object.getPrototypeOf(foo);
for(; proto !== null; proto = Object.getPrototypeOf(proto)) {
if(proto === Foo.prototype)
return true;
}
return false;
In ECMAScript3, there's no way to set a constructor property which behaves identically to the built-in one as user-defined properties are always enumerable (ie visible to for..in).
This changed with ECMAScript5. However, even if you set constructor manually, your code still has issues: In particular, it is a bad idea to set prototype to an instance of the parent-'class' - the parent constructor should not be called when the child-'class' is defined, but rather when child-instances are created.
Here's some ECMAScript5 example code for how it should be done:
function Pet(name) {
this.name = name;
}
Pet.prototype.feed = function(food) {
return this.name + ' ate ' + food + '.';
};
function Cat(name) {
Pet.call(this, name);
}
Cat.prototype = Object.create(Pet.prototype, {
constructor : {
value : Cat,
writable : true,
enumerable : false,
configurable : true
}
});
Cat.prototype.caress = function() {
return this.name + ' purrs.';
};
If you're stuck with ECMAScript3, you'll need to use a custom clone() function instead of Object.create() and won't be able to make constructor non-enumerable:
Cat.prototype = clone(Pet.prototype);
Cat.prototype.constructor = Cat;

Why is prototype assignment not working here?

var foo = {
name: "foo"
};
var bar = {};
bar.prototype = foo;
document.writeln("Bar name: " + bar.name + "<br />");
And here's what I got in browser:
Bar name: undefined
Why is this happening? Shouldn't Javascript look up name on bar, and then go up on foo and finds it? Why is it simply undefined?
Unfortunately, in Javascript x.prototype != "prototype of x". x.prototype means "if x is a constructor (=function), x.prototype will be a prototype of new x". If x is not a function, x.prototype doesn't make sense.
This is no more and no less confusing than the rest of the language. Remember, Mr. Eich had only 10 days to create it [ref].
To assign a prototype to an already created object, ES6 (Harmony) offers setPrototypeOf. In other engines, there's a vendor-specific hack o.__proto__=.... Mostly, it's a bad idea.
As others already correctly explained, the prototype system doesn't work like that in ECMAscript. You should instead use ECMAscripts Object.create method, which will do the magic for you.
var foo = {
name: "foo"
};
var bar = Object.create( foo );
console.log("Bar name: " + bar.name);
.create() will pretty much do this under the hood:
Object.create = (function(){
function F(){}
return function( o ){
F.prototype = o;
return new F()
}
})();
You can't directly set the prototype property on a plain object.
When you define a (constructor) function you can specify the prototype property of that function, and when that constructor is subsequently invoked the given property will be attached to the prototype chain of the new object.
So this would work:
var foo = { name: "foo" };
function Bar() { ... }
Bar.prototype = foo;
var b = new Bar();
// b.name now exists
However in ES5 you should use Object.create instead.
The prototype property, that is used for inheritance in JavaScript, is a member of the constructor function. It is not a member of the object that is created from the constructor function.
The object that is created from the constructor function has an internal property [[Prototype]] which is the same as the prototype property of the constuctor function. When you access a property on an object and the object does not have that property on its own, the [[Prototype]] object is searched for that property. But the [[Prototype]] property itself is not accessible from the language (it's only there for specification purposes).

In javascript why after reset the function's prototype need reset function prototype constructor too?

I always see code written like this:
function F() {};
var obj = {...}
F.prototype = obj;
F.prototype.constructor = F // why need this
After reseting the prototype: F.prototype = obj, why is the last line required? What does this reset the constructor too and is it always needed?
All Javascript objects inherit properties from the prototype object of their constructor.
Then, how do they also inherit properties from the Object class?
Remember that the prototype object is itself an object, it is created with the Object() constructor. This means that the prototype object itself inherits properties from Object.prototype.
If we use the default prototype object that is created when we define the F( ) constructor, we get a subclass of Object.To get a subclass of obj here, we must explicitly create our prototype object.
function F() {};
var obj = {...}
F.prototype = obj();
Since the prototype object was created with the obj() constructor,it has a constructor property that refers to the constructor of obj object.But we want F objects to have a different constructor that is F().That's why we've got to reassign this default constructor property.
F.prototype.constructor = F;
i hope this has helped you.

JavaScript inheritance and the constructor property

Consider the following code.
function a() {}
function b() {}
function c() {}
b.prototype = new a();
c.prototype = new b();
console.log((new a()).constructor); //a()
console.log((new b()).constructor); //a()
console.log((new c()).constructor); //a()
Why isn't the constructor updated for b and c?
Am I doing inheritance wrong?
What is the best way to update the constructor?
Further, please consider the following.
console.log(new a() instanceof a); //true
console.log(new b() instanceof b); //true
console.log(new c() instanceof c); //true
Given that (new c()).constructor is equal to a() and Object.getPrototypeOf(new c()) is a{ }, how is it possible for instanceof to know that new c() is an instance of c?
http://jsfiddle.net/ezZr5/
Okay, let's play a little mind game:
From the above image we can see:
When we create a function like function Foo() {}, JavaScript creates a Function instance.
Every Function instance (the constructor function) has a property prototype which is a pointer.
The prototype property of the constructor function points to its prototype object.
The prototype object has a property constructor which is also a pointer.
The constructor property of the prototype object points back to its constructor function.
When we create a new instance of Foo like new Foo(), JavaScript creates a new object.
The internal [[proto]] property of the instance points to the prototype of the constructor.
Now, the question arises that why doesn't JavaScript attach the constructor property to the instance object instead of the prototype. Consider:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function () {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
As you can see the constructor property is just another method of the prototype, like area in the example above. What makes the constructor property special is that it's used to initialize an instance of the prototype. Otherwise it's exactly the same as any other method of the prototype.
Defining the constructor property on the prototype is advantageous for the following reasons:
It's logically correct. For example consider Object.prototype. The constructor property of Object.prototype points to Object. If the constructor property was defined on the instance then Object.prototype.constructor would be undefined because Object.prototype is an instance of null.
It's treated no differently from other prototype methods. This makes the job of new easier since it doesn't need to define the constructor property on every instance.
Every instance shares the same constructor property. Hence it's efficient.
Now when we talk about inheritance, we have the following scenario:
From the above image we can see:
The derived constructor's prototype property is set to the instance of the base constructor.
Hence the internal [[proto]] property of the instance of the derived constructor points to it too.
Thus the constructor property of the derived constructor instance now points to the base constructor.
As for the instanceof operator, contrary to popular belief it doesn't depend on the constructor property of the instance. As we can see from above, that would lead to erroneous results.
The instanceof operator is a binary operator (it has two operands). It operates on an instance object and a constructor function. As explain on Mozilla Developer Network, it simply does the following:
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
To put it simply if Foo inherits from Bar, then the prototype chain for the instance of Foo would be:
foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
As you can see, every object inherits from the Object constructor. The prototype chain ends when an internal [[proto]] property points to null.
The instanceof function simply traverses the prototype chain of the instance object (the first operand) and compares the internal [[proto]] property of each object to the prototype property of the constructor function (the second operand). If they match, it returns true; and else if the prototype chain ends, it returns false.
By default,
function b() {}
then b.prototype has a .constructor property which is set to b automatically. However, you're currently overwriting the prototype and thus discarding that variable:
b.prototype = new a;
Then b.prototype does not have a .constructor property anymore; it was erased with the overwrite. It does inherit from a though, and (new a).constructor === a, and hence (new b).constructor === a (it is referring to the same property in the prototype chain).
Best to do is to simply setting it manually afterwards:
b.prototype.constructor = b;
You could also make a little function for this:
function inherit(what, from) {
what.prototype = new from;
what.prototype.constructor = what;
}
http://jsfiddle.net/79xTg/5/
constructor is a regular, non-enumerable property of the default value of the prototype property of function objects. Thus, assigning to prototype will lose the property.
instanceof will still work as it does not use constructor, but rather scans the prototype chain of the object for the (current) value of the function's prototype property, ie foo instanceof Foo is equivalent to
var proto = Object.getPrototypeOf(foo);
for(; proto !== null; proto = Object.getPrototypeOf(proto)) {
if(proto === Foo.prototype)
return true;
}
return false;
In ECMAScript3, there's no way to set a constructor property which behaves identically to the built-in one as user-defined properties are always enumerable (ie visible to for..in).
This changed with ECMAScript5. However, even if you set constructor manually, your code still has issues: In particular, it is a bad idea to set prototype to an instance of the parent-'class' - the parent constructor should not be called when the child-'class' is defined, but rather when child-instances are created.
Here's some ECMAScript5 example code for how it should be done:
function Pet(name) {
this.name = name;
}
Pet.prototype.feed = function(food) {
return this.name + ' ate ' + food + '.';
};
function Cat(name) {
Pet.call(this, name);
}
Cat.prototype = Object.create(Pet.prototype, {
constructor : {
value : Cat,
writable : true,
enumerable : false,
configurable : true
}
});
Cat.prototype.caress = function() {
return this.name + ' purrs.';
};
If you're stuck with ECMAScript3, you'll need to use a custom clone() function instead of Object.create() and won't be able to make constructor non-enumerable:
Cat.prototype = clone(Pet.prototype);
Cat.prototype.constructor = Cat;

Categories

Resources