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.
Related
function Product(name, price) {
this.name = name;
this.price = price;
}
const p1 = new Product('Pen', 20);
const p2 = Object.create(p1);
console.log(p1.constructor.prototype === p1.__proto__); // true
console.log(p2.constructor.prototype === p2.__proto__); // false
My understanding was these two are always equal (as in the first console.log statement).
But, while doing some tweaks I found this surprising result (second console.log statement).
Can someone please clear up my understanding about the relationship between prototype and __proto__. Thanks in advance!
This only works for instances created using new from constructors that follow the standard prototype pattern. These objects will inherit from the constructors .prototype object, which has a .constructor property pointing back to the constructor. This means when accessing the inherited .constructor, we can find the prototype object that we're inheriting on it.
However, it doesn't work for arbitrary objects that have their own .constructor property (e.g. {constructor: null}) or for objects that don't inherit directly from a constructor's prototype object, such as your p2.
To clarify what's happening in your code without using new:
const Product = Object.create(Function.prototype);
Product.prototype = Object.create(Object.prototype);
Product.prototype.constructor = Product;
const p1 = Object.create(Product.prototype);
p1.name = "Pen";
p1.price = 20;
console.assert(Product.prototype == Object.getPrototypeOf(p1));
console.assert(!p1.hasOwnProperty("constructor") && p1.constructor == Product);
console.assert(p1.constructor.prototype == Product.prototype);
console.assert(p1.constructor.prototype == Object.getPrototypeOf(p1));
const p2 = Object.create(p1);
console.assert(p1 == Object.getPrototypeOf(p2));
console.assert(!p2.hasOwnProperty("constructor") && p2.constructor == p1.constructor);
function Person(name, age, height) {
this.name = name,
this.age = age,
this.height = height
}
var john = new Person("John", 24, 175);
What I read should be avoided:
john.__proto__.fact = "I am a humanly human!"
What should be done instead:
Person.prototype.fact = "I am a humanly human!"
If you want to add to the prototype of the object john refers to, doing so through john.__proto__ gives the impression to the reader of the code that this change is specific to john somehow, which it isn't; it affects all objects that use that prototype (current and future). Using Person.prototype doesn't give that impression, it correctly indicates what you're doing.
Separately, note that not all objects (not even all objects with prototypes) have __proto__, because __proto__ is inherited from Object.prototype, but not all objects inherit from Object.prototype. For that reason, in new code, it's best to avoid __proto__ entirely; use Object.getPrototypeOf instead if you need to get the prototype of an object: Object.getPrototypeOf(john).
In a comment you've answered the question of why you'd want to do this with:
To add methods such that they are not present in every Person object you create.
...but that's exactly what adding to john.__proto__ would do: Add the method to every Person object (indirectly through the prototype), current and future, exactly like adding to Person.prototype — because those (and Object.getPrototypeOf(john)) are all just different ways of getting to the same object:
function Person(name) {
this.name = name;
}
var john = new Person("John");
console.log(john.__proto__ === Person.prototype); // true
console.log(Object.getPrototypeOf(john) === Person.prototype); // true
var paul = new Person("Paul");
john.__proto__.someNewMethod = function() {
console.log(this.name);
};
john.someNewMethod(); // "John"
paul.someNewMethod(); // "Paul"
If you want to add a method just to the object john refers to, don't use __proto__ or Person.prototype at all: Just do:
john.niftyMethod = function() { /*....*/ };
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 known this has been asked hundreds of times, however, I can't seem to grasp the concept of prototype
Here's my sample script
var config = {
writable: true,
enumerable: true,
configurable: true
};
var defineProperty = function(obj, name, value) {
config.value = value;
Object.defineProperty(obj, name, config);
}
var man= Object.create(null);
defineProperty(man, 'sex', "male");
var person = Object.create(man);
person.greet = function (person) {
return this.name + ': Why, hello there, ' + person + '.'
}
var p=Object.getPrototypeOf(person);
alert(p.sex);//shows male
person.prototype.age=13;//why there is a error said the prototype is undefined? I thought it supposed be man object...
var child=function(){}
child.prototype.color="red";//why this line doesn't show error? both child and person are an object .
alert(child.prototype.color);//shows red
var ch=Object.getPrototypeOf(child);
alert(ch.color);//why it is undefined? it is supposed red.
Hope you can give me some helps... thanks.
Updated:
Thanks your guys kindly help, Based on Elclanrs's answer, Below is what I learned.
Function is the one of the build-in objects in javascript. the 3 format creation function object are equal.
var function_name = new Function(arg1, arg2, ..., argN, function_body)
function function_name(arg1, arg2, ..., argN)
{
...
}
var function_name=function(arg1, arg2, ..., argN)
{
...
}
So, that is why create a prototype chain we have to create a function and then call it with the new keyword .
Function.prototype is the reference to All the Function object prototype.
Cheers
The prototype property only exists on functions, and person is not a function. It's an object.
Here's what's happening:
var man = Object.create(null); // man (object) -> null
man.sex = "male";
var person = Object.create(man); // person (object) -> man (object) -> null
person.greet = function () { ... };
var p = Object.getPrototypeOf(person); // man (object) -> null
alert(p.sex); // p is the same object as man
person.prototype.age = 13; // person doesn't have a prototype
var child = function () {}; // child (function) -> Function.prototype
// -> Object.prototype -> null
child.prototype.color = "red"; // child has a prototype
var ch = Object.getPrototypeOf(child); // Function.prototype
alert(ch.color); // ch is not the same as color.prototype
// ch is Function.prototype
For more information I suggest you read this answer: https://stackoverflow.com/a/8096017/783743
Edit: To explain what's happening in as few words as possible:
Everything in JavaScript is an object except primitive values (booleans, numbers and strings), and null and undefined.
All objects have a property called [[proto]] which is not accessible to the programmer. However most engines make this property accessible as __proto__.
When you create an object like var o = { a: false, b: "something", ... } then o.__proto__ is Object.prototype.
When you create an object like var o = Object.create(something) then o.__proto__ is something.
When you create an object like var o = new f(a, b, ...) then o.__proto__ is f.prototype.
When JavaScript can't find a property on o it searches for the property on o.__proto__ and then o.__proto__.__proto__ etc until it either finds the property or the proto chain ends in null (in which case the property is undefined).
Finally, Object.getPrototypeOf(o) returns o.__proto__ and not o.prototype - __proto__ exists on all objects including functions but prototype only exists on functions.
I think you might be mixing concepts. Try grasping the concept of prototypes with classic prototype inheritance first, then you can get into all the new Object stuff.
In JavaScript, every object (numbers, strings, objects, functions, arrays, regex, dates...) has a prototype which you can think of as a collection of methods (functions) that are common to all current and future instances of that object.
To create a prototype chain you have to create a function and then call it with the new keyword to specify that it is a constructor. You can think of constructors as the main function that takes the parameters necessary to build new instances of your object.
Having this in mind, you can extend native objects or create your own new prototype chains. This is similar to the concept of classes but much more powerful in practice.
Similar to your example, you could write a prototype chain like this:
// Very basic helper to extend prototypes of objects
// I'm attaching this method to the Function prototype
// so it'll be available for every function
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype);
}
// Person constructor
function Person(name, age, sex) {
// Common to all Persons
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype = {
// common to all Persons
say: function(words) {
return this.name +'says: '+ words;
}
};
// Student constructor
function Student(name, age, sex, school) {
// Set the variables on the parent object Person
// using Student as a context.
// This is similar to what other laguanges call 'super'
Person.call(this, name, age, sex);
this.school = school; // unique to Student
}
Student.inherits(Person); // inherit the prototype of Person
var mike = new Student('Mike', 25, 'male', 'Downtown'); // create new student
console.log(mike.say('hello world')); //=> "Mike says: hello world"
In newer version of JavaScript (read EcmaScript) they added new ways to deal with objects and extend them. But the concept it's a bit different from classical prototype inheritance, it seems more complicated, and some more knowledge of how JS works underneath would help to really understand how it works, plus it doesn't work in older browsers. That's why I suggest you start with the classical pattern for which you'll find accurate and abundant information on the internet.
Basically everyone writing about member enumeration in JavaScript heavily advocates the use of the hasOwnProperty method as to avoid going up the prototype-chain.
I understand that this is a form of defensive programming as to prevent iterating over members that are added, for example, to the Object.prototype. But what about the other inherited members? Say, members that are very close in the prototype chain...members that you actually Want to be enumerated over.
Let's say I have the following:
var beget = function (o) { // http://javascript.crockford.com/prototypal.html
function F() {};
F.prototype = o;
return new F();
};
var john = { name: 'john', surname: 'grech' },
mary = beget(john),
p;
mary.age = 42; //augmenting 'mary'
// 'surname' in mary => true
// mary.hasOwnProperty('surname') => false
for (p in mary) {
//skipping over non-direct members, meaning that we also skip members
//inherited from 'john'
if (!mary.hasOwnProperty(p)) {
continue;
}
console.log(p);
}
In the above sample, only age will be displayed, since age is the only direct-member of mary...the other two members, name and surname, are up the prototype chain.
But obviously, I want all the 3 members to be iterated over in the for..in construct; but if you remove the hasOwnProperty, you can then get members from Object.Prototype if someone adds functions to it.
So this is my dilemma.
Do you use prototypal inheritance in combination with the hasOwnProperty method but risk getting members that are too far up the chain during enumeration?
Or do you use the other forms of inheritance that add members directly to the object rather than the prototype?
Hm. You are saying " very close in the prototype chain", but actually, what does it mean very close? Is the three level deep "close" or "far".
Anyway, you could change a bit beget function and implement own hasOwnProperty function for every object, which would go through the prototype chain only till the Object level. This will solve your dilemma of getting members which are added to the Object.prototype by not using hasOwnProperty. Code attached bellow:
var beget = function (o) { // http://javascript.crockford.com/prototypal.html
function F() {
this.hasOwnProperty = function(key) {
return (key != "hasOwnProperty"
&& Object.prototype.hasOwnProperty.call( this, key )
|| o.hasOwnProperty( key )
);
}
};
F.prototype = o;
return new F();
};
var john = { name: 'john', surname: 'grech' },
mary = beget( john ),
p = beget( mary );
mary.age = 42; //augmenting 'mary'
mary.name = "mary";
p.size = "38";
// testing prototype of Object.
Object.prototype.not_own = function(){}
for(var i in p) {
console.debug('Key',i, p.hasOwnProperty(i));
}
// p.hasOwnProperty("size"); // -> true
// p.hasOwnProperty("age"); // -> true
// p.hasOwnProperty("name"); // -> true
// p.hasOwnProperty("not_own"); // -> false
If you need to iterate over the prototypal chain of an object you can use hasOwnProperty to skip direct members (as you said). This will of course also iterate through whichever other member that was added to the prototype of that object (Object.Prototype etc..). There's no way to avoid this.
It's like asking how to avoid enumerating over certain members of a car = {yellow, green, black} object (pseudocode)... you don't... you simply skip certain members based on their value.
Adding members directly to an object isn't really a form of inheritance, unless of course you create objects using the begetObject() technique... because it uses the Prototype to add members.