In Stoyan Stefanov's book Object-Oriented javascript, on page 103 he has the following. However when I try this, I get a different result with h instanceof Object. Am I missing something, has something in JS changed since or is this an error in the book.
>>> function Hero(){}
>>> var h = new Hero();
>>> var o = {};
>>> h instanceof Hero;
true
>>> h instanceof Object;
false //true in Google Chrome
>>> o instanceof Object;
true
If that's what the book says, then the book
is incorrect. (And searching the book content in Amazon.com confirms the error.)
Your true result that you get in Google Chrome is the correct result.
While the h object inherits from the .prototype on the Hero function, that .prototype inherits from the .prototype on the Object function. This means that h inherits both from Hero.prototype and Object.prototype, and is considered an instance of both constructors.
The only way it wouldn't be would be if Hero.prototype was an object that did not inherit from Object.prototype. But in that example, it uses the default object, so it does indeed inherit.
Using the instanceof operator you don't test whether something was created by a certain constructor, but whether something inherits from a certain object (whether a certain object is in the prototype chain of something). foo instanceof F has exactly the same result as a recursive* Object.getPrototypeOf(foo) === F.prototype
var F = function() {};
var foo = new F();
foo instanceof F // true
Object.getPrototypeOf(foo) === F.prototype // true
F.prototype = {}; // changed the prototype of F
foo instanceof F // false
Object.getPrototypeOf(foo) === F.prototype // false
foo instanceof Object // true
Object.getPrototypeOf(Object.getPrototypeOf(foo)) === Object.prototype // true
With that in mind, it is pretty obvious that if you don't change the prototype of a function to an object which doesn't inherit from Object.prototype, all the instances constructed with that function as constructor will inherit from Object.prototype, so they will be instances of Object.
F.prototype = Object.create(null);
var bar = new F();
bar instanceof F // true
bar instanceof Object // false
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
instanceof shim (just theoretical purposes, there is no practical use for it):
function instanceOf(object, constructor) {
if (!object) return false;
var object = Object.getPrototypeOf(object);
if (object === constructor.prototype) return true;
return instanceOf(object, constructor);
}
Related
I have the following 2 functions:
function Dog() {}
function Cat() {}
I set Dog.prototype = new Cat()
I then create a dog instance:
let dog = new Dog();
Why is dog instanceof Dog === true. I understand why dog instanceof Cat === true because I just set it to Cat's prototype but how is there still some reference to Dog prototype when it has been overridden even before the instance was created? How would I make make dog instanceof Dog === false?
As mentioned in MDN docs
The instanceof operator tests whether the prototype property of a
constructor appears anywhere in the prototype chain of an object.
That means instanceof will check the prototype property of the constructor with the __proto__ of the Object, not the value that prototype is holding. You can check this as following
console.log(Dog.prototype === dog.__proto__) // prints -> true
console.log(Dog.prototype === Object.getPrototypeOf(dog)) // prints -> true
What you are doing is merely changing the prototypes's `value. It still is the same property.
Modified:
Take a look at simplified implementation on instanceof method
function instanceOf(object, constructor) {
return Object.getPrototypeOf(object) === constructor.prototype;
}
Here, you can see that instanceof returns true, if reference of Object.getPrototypeOf(object) is equal to constructor.prototype. In your case Dog.prototype is Cat, and Object.getPrototypeOf(dog) is also Cat. That's why instanceof will always return true.
Reference
Link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
Search for Object.getPrototypeOf(o) === C.prototype
I am reading about prototype chaining in JS. I came across this schematic online.
My question is:
Since function A and B are Object of type Function shouldn't there be a Function and a Function.prototype Object somewhere in the inheritance tree?
The constructor functions are not being diagrammed hierarchically in the prototype chain, the Objects they construct are the focus of the diagram.
There is an important distinction (and confusion) in the difference between [[proto]] (accessible via obj.__proto__ where obj is any Object) and the Prototype property of an object, viz. obj.prototype.
This snippet may explain:
function A(name){
this.name = name
this.getName = function(){ return name }
}
function B(name){
A.call(this, name)
}
var b = new B('yep')
var anotherB = new B('me too')
console.log(b.getName()) // yep
/* both B & A constructors inherit from Function but B doesn't inherit from A */
console.log(B instanceof Function && A instanceof Function) //true
console.log(B.prototype === A.prototype) //false
console.log(B.__proto__ === A.__proto__) //true
console.log(B instanceof A) //false
/* an instance of B is not an instance of A */
console.log(b instanceof B) //true
console.log(b instanceof A) //false
/* an instance of B has the prototype of B but not the same [[proto]] as B */
console.log(B.prototype.isPrototypeOf(b)) //true
console.log(b.__proto__ === B.__proto__ ) //false
/* instances of B have the same [[proto]] but not the same [[proto]] as B */
console.log(b.__proto__ === anotherB.__proto__ ) //true
function B does not inherit from function A. Both function A and function B inherit from Function which inherits from Object. They both have identical Prototype chains (abbreviated).
function A: function A -> Function -> Object
function B: function B -> Function -> Object
Which is different from the Objects they construct. In the case of the Object returned from function B, the prototype chain is B -> A -> Object.
Why do the following two lines return different results?
("test" instanceof String) // returns false
("test".constructor == String) // returns true
Tested in the console of chrome version 28.0.1500.95 m
Does it work slightly differently for native types?
constructor is just a property of the internal [[prototype]] property, that can easily be manipulated:
function A(){}
function B(){}
A.prototype.constructor = B;
var a = new A();
console.log(a.constructor); //B
The instanceof operator however checks the internal prototype chain and is not so easily to be fooled, even if you change the complete prototype property of the constructor function:
function A(){}
function B(){}
A.prototype = B.prototype;
var a = new A();
console.log(a instanceof A); //true
console.log(a instanceof B); //false
So, why is "test" instanceof String === false but ("test".constructor == String) === true?
First of all, "test" is a primitive and primitives are never an instance of anything. What actually happens when you use instanceof is that the internal [[HasInstance]] method of the constructor is called with the possible instance as an argument. So a instanceof A translates roughly to:
`A.[[HasInstance]](a)`
The ECMA Specs have this to say to [[HasInstance]]: http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.3
[[HasInstance]] (V)
Assume F is a Function object.
When the [[HasInstance]] internal method of F is called with value V,
the following steps are taken:
If V is not an object, return false.
....
In other words: If the left hand side of instanceof is not an object, the operator will return false.
("test".constructor == String) === true works for a different reason: If you try to access a property of a primitive, the primitive will be temporarily converted into an object. So "test".constructor is roughly equal to:
(new String("test")).constructor
in which case you are actually creating an object, with a constructor function and requesting the constructor property afterward. So it is no surprise, that it will return String.
The main difference is that instanceof inspects the object's prototype chain whereas checking the constructor only checks to see if it was created from the same constructor.
Example:
function MyObject() {
this.sayHi = function() { alert('Hi!'); }
}
var x = new MyObject();
alert(x.constructor === Object);
alert(x instanceof Object);
I have a question about the following canonical object.create method:
Object.create = function(o, props) {
function F() {}
F.prototype = o;
if (typeof(props) === "object") {
for (prop in props) {
if (props.hasOwnProperty((prop))) {
F[prop] = props[prop];
}
}
}
return new F();
};
On line 3 of the above code we set the prototype property of the F object to the o argument's prototype.
I would have thought this meant that both o and F point to the same prototype and therefore point to the same set of members.
But the code then goes onto copy all the members in the prop in props loop.
What is the point of setting the prototype in line 3 if we then go onto copy all the members manually?
There's a mistake in the version of Object.create in your question: The loop attaches the properties to the constructor function F (not to the returned object, or its prototype) which means they're not accessible in the created object.
The properties of the second parameter to Object.create are supposed to be copied to the newly created object. The Mozilla documentation for Object.create puts it like this:
If specified and not undefined, an object whose enumerable own properties (that is, those properties defined upon itself and not enumerable properties along its prototype chain) specify property descriptors to be added to the newly-created object, with the corresponding property names.
Try running the following code with the version of Object.create in the question:
o = Object.create(
{a: "prototype's a", b: "prototype's b"},
{a: "object's a"}
);
You'll find that o.a == "prototype's a" and o.b == "prototype's b", "object's a" is lost.
The following version of the function would probably be more useful:
Object.create = function(o, props) {
var newObj;
// Create a constructor function, using o as the prototype
function F() {}
F.prototype = o;
// Create a new object using F as the constructor function
newObj = new F();
// Attach the properties of props to the new object
if (typeof(props) === "object") {
for (prop in props) {
if (props.hasOwnProperty((prop))) {
newObj[prop] = props[prop];
}
}
}
return newObj;
};
Let's try it out with the same example:
o = Object.create(
{a: "prototype's a", b: "prototype's b"},
{a: "object's a"}
);
The new object o is created with a prototype that has properties a and b and it's own property a.
Let's look at o.b first: o.hasOwnProperty("b") will return false, because o does not have a property called b. That's where the prototype comes in; because there is no property b it is looked up on the prototype, and therefore o.b === "prototype's b".
On the other hand, o.hasOwnProperty("a") will return true, because o does have an a property. o.a == "object's a" and nothing is looked up from the prototype.
As pointed out in #chuckj's answer, the correct implementation of Object.create is more complicated than this. For more details, see John Resig's post on ECMAScript 5 Objects and Properties.
The code you present is not equivalent to Object.create() as defined by the ECMA standard. The members of the second parameter, here called prop, is supposed to be a set of descriptors to be defined on the resulting object, not copied to the constructor function. This is more accurate (but not exacly right either),
Object.create = function(o, props) {
function F() {}
F.prototype = o;
var result = new F();
if (typeof(props) === "object")
for (prop in props)
if (props.hasOwnProperty(prop) && typeof(props[prop].value) != "undefined")
result[prop] = props[prop].value;
return result;
};
The props parameter contains the property descriptors for the members of the new object you want to be different than specified in the prototype, o. The values are not supposed to be copied literally into the object rather they are supposed to be processed as if you called Object.defineProperties(), above simulated by assigning the value part of the descriptor to the new object. Object.create() cannot be accurately polyfilled to ECMA 3 since it can be used to specifiy properties with accessor functions, though the above will work for props which use value instead of get or set.
If you are not interested in a polyfill version, the following is an accurate description of what Object.create() does, assuming the existence of both __proto__ and Object.defineProperties().
Object.create = function (o, props) {
if (typeof(o) !== "object" && o != null) throw new TypeError();
var result = new Object();
if (o != null)
result.__proto__ = o;
if (typeof(props) !== "undefined")
Object.defineProperties(result, props);
return result;
};
Think of F as a function that returns a new instance of an object and F.prototype a reference to the object that the new instance is borrowing properties from.
Instances created with F have their own property set independant of F.prototype.
When a property cannot be found in an incance of F then the runtime will step up the prototype chain and peek to see if the property exists in F.prototype.
This is why you would want to copy some and inherit others.
The point of the Prototype is to provide class-like code reuse/property storage.
Think of F.prototype as the class instances of F as the object.
I'm messing around with the prototype chain and noticed something I can't explain. I'm still learning all of this, so it's probably a mistake i've made. I'm trying to do some multi-inheritance, like so many others. I noticed the prototype object looks a lot like a hash/dictionary, I thought, why not use something like underscore.extend to merge multiple prototype objects together as one.
function A(){this.value="A";};
A.prototype.funcA = function (){console.log(this.value);}
function B(){this.value="B";};
B.prototype.funcB = function (){console.log(this.value);}
function C(){
// fix constructor
this.constructor = C;
// 'inherit' properties
A.call(this);
B.call(this);
};
// gobble up the prototype chains of A and B
C.prototype = new underscore.extend(A.prototype,B.prototype);
C.prototype.funcC = function (){console.log(this.value);}
var c = new C();
> c instanceof C
true
> c instanceof A
true
> c instanceof B
false
I'm really surprised to get a true at all here. Can anyone explain what's going on here?
UPDATE
I removed underscore's extend method from the code, as suggested, and this works a lot better. thanks!
function extend(destination, source) {
for (var property in source) {
if (source.hasOwnProperty(property)) {
destination[property] = source[property];
}
}
return destination;
};
function A(){this.value="A";};
A.prototype.funcA = function (){console.log(this.value);}
function B(){this.value="B";};
B.prototype.funcB = function (){console.log(this.value);}
function C(){
this.constructor = C;
A.call(this);
B.call(this);
};
var destination = {};
destination = extend(destination,A.prototype);
destination = extend(destination,B.prototype);
C.prototype = destination;
C.prototype.funcC = function (){console.log(this.value);}
var c = new C();
> c
{ constructor: [Function: C], value: 'B' }
> c instanceof A
false
> c instanceof B
false
> c instanceof C
true
There is no multiple inheritance in JavaScript, because one object can have only one prototype. To prove it is enough to see ECMAScript 5 Object.getPrototypeOf method which of course returns only one value. For older interpreters you could try __proto__ property (non-standard) of simply obj.constructor.prototype.
The example you've made give you a possibility to have all features from two different prototypes, however it brakes the prototype chain - this is why instanceof operator returns false for A and B. In fact prototypes of A or B are not prototypes of your object, but the mixin of them which you have made using the extend function. The function name is very misleading (however such name is used by some of frameworks and libraries) - because we don't extend any object (in object-oriented programming meaning) - we build a mixin of two object - which is completely different design pattern.
Bit out off topic - if you're experimenting with objects and prototypal inheritance - try to play with Object.create method (of ECMAScript 5). It's very useful in this case.