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
Related
The following code logs 'true' 4 times:
var menuItem = {
name: "New menuItem",
};
function food(name) {
if(name) this.name = name;
//this.resourceType = "food";
}
food.prototype = menuItem;
function drink(name) {
if(name) this.name = name;
//this.resourceType = "drink";
}
drink.prototype = menuItem;
var burger = new food();
var coke = new drink();
console.log(buger instanceof food);
console.log(burger instanceof drink);
console.log(coke instanceof food);
console.log(coke instanceof drink);
However if I comment out the following two lines:
//food.prototype = menuItem;
//drink.prototype = menuItem;
Then the code does what I want and logs true for "buger instanceof food" and "coke instanceof drink".
Is there a way of checking if the menuItem is an instance of either food or drink correctly while they both share the same prototype (menuItem)?
I'd prefer not to have to store the type like so:
this.resourceType = "food";
If there is a better way of doing it.
For each constructor, create a new object to use as the prototype of that constructor, and have each new prototype object use menuItem as its prototype:
food.prototype = Object.create(menuItem);
So the prototype chain for a food instance and drink instance now looks like:
[food instance] > [food prototype] > [menuItem]
[drink instance] > [drink prototype] > [menuItem]
The old chain looked like:
[food instance] > [menuItem]
[drink instance] > [menuItem]
As you can see, in the old chain, a food instance and drink instance really had the same prototype parent, so a food-constructed object and drink-constructed object has the same prototype parent. Under the new system, food and drink have separate prototype parents.
MDN has a good description of instanceof:
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.
So, when you test burger instanceof drink you're testing "is drink.prototype in the prototype chain of burger?". Previously, drink.prototype was equal to menuItem, so you were really testing "is menuItem in the prototype chain of burger?". Now, drink.prototype is its own unique value, separate from food.prototype, so the result is false.
This is a kind of question very debated, but I think the reason is the lack of good documentation and good books on the subject.
When I study a language I do a lot of digging even if some of my tests are absurd, but I think the only way to understand things is doing all kinds of experiments.
I'm beginning with JavaScript and as much I code as more I'm confused.
Let's view the code (forget the no-senses by now and consider only the outputs):
function Vehicle()
{
this.color = 'Blue'
}
var car = new Vehicle()
console.log('Vehicle.constructor: ', Vehicle.constructor)
console.log('car.constructor: ', car.constructor)
console.log('Vehicle.prototype: ', Vehicle.prototype)
console.log('car.prototype: ', car.prototype)
console.log('Vehicle.constructor.prototype: ', Vehicle.constructor.prototype)
console.log('car.constructor.prototype: ', car.constructor.prototype)
console.log('Vehicle.prototype.constructor: ', Vehicle.prototype.constructor)
console.log('car.prototype.constructor: ', car.prototype.constructor)
Output:
Vehicle.constructor: Function()
car.constructor: Vehicle()
Vehicle.prototype: Vehicle {} // curly braces here
car.prototype: undefined
Vehicle.constructor.prototype: function()
car.constructor.prototype: Vehicle {} // curly braces here
Vehicle.prototype.constructor: Vehicle()
TypeError: car.prototype is undefined
My conclusions:
Vehicle.prototype == car.constructor.prototype == Vehicle {} // curly braces here
Vehicle.prototype.constructor == car.constructor == Vehicle() // parenthesis here
Vehicle.constructor == Function() // uppercase 'F'
Vehicle.constructor.prototype == function() // lowercase 'f'
car.prototype == undefined // undefined but not reported as error
car.prototype.constructor // Type error. Here 'car.prototype' is reported as an error
Now let's consider the similar code:
var car = {color: 'Blue'}
console.log('car.constructor: ', car.constructor)
console.log('car.prototype: ', car.prototype)
console.log('car.constructor.prototype: ', car.constructor.prototype)
console.log('car.prototype.constructor: ', car.prototype.constructor)
Output:
car.constructor: Object()
car.prototype: undefined
car.constructor.prototype: Object {} // curly braces here
TypeError: car.prototype is undefined
As we can see, here 'car.prototype' is only undefined, but 'car.prototype.constructor' is undefined and also 'TypeError'
The code above is tested in Firebug. I don't know this is Firebug's fault or JavaScript fault.
All of this puzzled me.
If this is OOP in JavaScript I think this is more ODP - Object (Dis)oriented Programming
EDIT
1) Why car.prototype is undefined when car.prototype.constructor is TypeError
2) Why both functions and objects have constructors and prototypes (see code above)?
3) What the meaning of this:
Vehicle.constructor.prototype: function()
Vehicle.prototype.constructor: Vehicle()
car.constructor.prototype: Vehicle {}
You should remember forever: Every function in JavaScript is actually a Function object, as Function inherited from Object, any function is Object too. So, keeping in mind this sentence, look at this:
(function f(){}) instanceof Function; // true
(function f(){}) instanceof Object; // true, as Function is an instance of Object
({}) instanceof Object; // true
({}) instanceof Function; // false!
Function.prototype instanceof Object; // true
Function instanceof Object; // true, as all objects in JS are inherited from Object
Object instanceof Function; // true, as Object is a constructor function, therefor:
Function instanceof Function; // true
Object instanceof Object; // true, but:
Date instanceof Date; // false
Function.prototype.constructor === Function; // true
Function.constructor === Function; // true
typeof Object === 'function'; // true, as Object is a constructor function
So, different braces indicate that prototype is always an object (curly braces), if it is defined, and constructor is always a function. That's all.
Any time you declare an object using object literal notation
var newObject = {foo: 'bar'};
You are creating an object that inherits from 'Object()' and has no prototype of it's own.
Notice when you call 'car.constructor' it returns 'Object()'. This is because that is the constructor JS uses in object literal notation.
When you call 'car.prototype' it is undefined because object literals have no prototype of their own.
When you call 'car.constructor.prototype' it returns an empty object since that is the essentially the value of 'Object()'. It just creates objects.
in order for your objects to have their own prototypes you must establish a constructor and use
'new myObject()' to declare your objects.
I hope I've helped answer your question. Here are a few links that have more info:
Adding Prototype to JavaScript Object Literal
http://doctrina.org/Javascript-Objects-Prototypes.html
http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/
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);
}
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 simple class in javascript:
function foo() {
this.bar = "bar";
}
var test = new foo;
console.log(foo.prototype,foo.__proto__)
/*output: foo {
constructor: function foo() {
__proto__: Object
}
,
function Empty() {}
*/
console.log(test,test.prototype,test.__proto__,test.__proto__.__proto__)
/*output: foo {
bar: "bar"
__proto__: foo
}
,
undefined
,
foo {
constructor: function foo() {
__proto__: Object
}
,
Object {
...
}
*/
What i dont understand:
At the first log the foo.prototype had the __proto__ attribute which was an Object
At the second log the test.__proto__ had the __proto__ attribute which was an Object
When to use __proto__ and when prototype, what is the difference?
UPDATE:
In John Resig's blog in the instanceOf section there is something waht I don't understand:
If i use var asd = "asd";Object.getPrototypeOf(asd) it throws a TypeError but
If i use var dsa = new String("dsa");Object.getPrototypeOf(dsa) it returns String
But asd.constructor.prototype == dsa.constructor.prototype is true
Why is the Object.getPrototypeOf(asd) throws error? This is a string, isn't it?
Always use prototype or Object.getPrototypeOf.
__proto__ is non-standard and has been deprecated by Mozilla.
John Resig has a good blog entry about it.
The reason why test.prototype is undefined is because you created a new object that does not have a constructor prototype. Here's an example of when to use Object.getPrototypeOf.
js> function foo(){}
js> typeof foo.prototype;
object
js> var f = new foo();
js> typeof f.prototype;
undefined
js> typeof Object.isPrototypeOf(f);
object
js> typeof f.constructor.prototype;
object
js> foo.prototype === Object.getPrototypeOf(f);
true
js> foo.prototype === f.constructor.prototype;
true
As you can tell, inheritance in JavaScript is tricky. Lets look at an example:
js> typeof "asdf";
string
js> typeof String("asdf");
string
The string literal is of type string. The same is true when calling String() as a function. Now, because of behavior of the new operator, a new object is created, with the prototype of String() as its parent.
js> var s = new String("asdf");
js> typeof s;
object
Because JS likes to coerce things, you can get at the string literal a few ways:
js> s
asdf
js> s.valueOf();
asdf
js> typeof s
object
js> typeof s.valueOf();
string
Prototypal Inheritance in JavaScript by Crockford helped me a lot when learning about JS inheritance.
From Mozilla's Strings page:
String objects may be created by
calling the constructor new String().
The String object wraps JavaScript's
string primitive data type with the
methods described below. The global
function String() can also be called
without new in front to create a
primitive string. String literals in
JavaScript are primitive strings.
__proto__ is an intermediary object between an object and it's prototype. The biggest benefit in using it is that you can change the prototype chain for an object entirely without modifying the instance or the prototype.
Example:
function F() {}
F.prototype.a = 1;
var f = new F();
f.__proto__ = { b : 2 };
"a" in f => false;
"b" in f => true;
But as Jeremy said, __proto__ is deprecated. The only use case would be if you would like to add a set of properties to an object, changing its prototype without having to iterate through each one. Not a big deal.