Accessing objects and prototype in Javascript - javascript

I'm not quite getting object creation and adding/extending methods in JavaScript. I know everything is an object and the use of functions as constructors, but I don't quite get prototype and creating/calling new methods.
var c1 = {
name: "Neil",
};
var c2 = function() {
this.name = "Neil";
};
With both the above I can add new stuff:
c1.town = "a town";
c2.town = "a town";
c1.setTown = function(newTown) { this.town = newTown;};
c2.setTown = function(newTown) { this.town = newTown;};
Where I fall over is with the function approach I can do this:
c2.prototype.setTown2 = function(newTown) { this.town = newTown;};
c3 = new c2();
c3.setTown2("new3");
1: What is the difference between setTown and setTown2 and why for c3 can I call c3.town="x" and c3.setTown2("x") but not call c3.setTown("x"); ?
2: I don't seem to have access to 'prototype' for the c1 (the literal constructor approach), why is this?
thanks.

This is because JavaScript literal constructors like c1 create an actual Object, while functions with this like c2 create constructors that can be used to create objects like you did with c3. Here's an analysis of your code through JavaScript comments:
//This is a literal object with property name equal to "Neil":
var c1 = {
name: "Neil",
};
//We do not need to access the prototype here because c1 is an object, not a constructor:
console.log(c1.name);
//This is a constructor that creates an object with property name of "Neil".
var c2 = function() {
this.name = "Neil";
};
//This creates a property town of "a town" on c1. This works because c1 is a regular object.
c1.town = "a town";
//This creates a property town of "a town" on c2. However, if you create an object with c2, the object will not inherit town because it is not on the prototype.
//This does not throw an error because even though c2 is a function, you can still set the property town on it because this property is what's called a _static property_. Static properties are properties that are set without the prototype like the property below:
c2.town = "a town";
//With c1, we do not need to access prototype because it's a regular object and with c2, we do not need to access prototype because it's a static property.
console.log(c1.town, c2.town);
//This works the same as above, except now, we're using functions instead of regular properties.
c1.setTown = function(newTown) { this.town = newTown;};
c2.setTown = function(newTown) { this.town = newTown;};
//This sets the town property of c1 like with a regular object:
c1.setTown("HI!");
//This sets the static property town of c2 because "this" in the static method c2.setTown is c2, so "this.town" is "c2.town", or the static property town which we set above:
c2.setTown("HI!");
//Both of the following outputs "HI!" because of the .setTown() calls above.
console.log(c1.town, c2.town);
//This method is set on the prototype of c2, meaning that objects made with c2 will inherit this method.
c2.prototype.setTown2 = function(newTown) { this.town = newTown;};
//This is an object made with the constructor c2. It inherits name because of the actual constructor function and it inherits setTown2 from the prototype. However, it does NOT inherit c2.town and c2.setTown because those are static properties not on the prototype.
c3 = new c2();
//This sets the town property of c3 because c3 inherited the setTown2 method from c2.prototype, so that method now sets the properties of c3.
c3.setTown2("new3");
//c3.name outputs "Neil" because of the c2 constructor function and c3.town outputs "new3" because of the above c3.setTown2() call:
console.log(c3.name, c3.town);

Are you familiar with inheritance? A common concept in programming, this is the way to simulate inheritance in javascript.
Basically, when you add new methods or variables to the prototype, you modify the main structure of the object... So when you decide to create a new object from the modify 'class' (there are no classes in JS I know), the only method it remains are the ones inside the prototype.
More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

1: What is the difference between setTown and setTown2
They're both function, however you create a new function every time you want to add that as method, where with prototype you automatically inherit it:
var c3 = new c2();
var c4 = new c2();
c3.setTown = function(newTown) { this.town = newTown;};
c4.setTown = function(newTown) { this.town = newTown;};
console.log(c3.setTown === c4.setTown) // false
console.log(c3.setTown2 === c4.setTown2) // true
Also,setTown is a property of the objects c3 and c4, where setTown2 is not. It's inherited. It means:
console.log(c3.hasOwnProperty("setTown")); // true
console.log(c3.hasOwnProperty("setTown2")); // false
And therefore Object.keys won't return setTown2; but if you execute a for…in loop you will get both own properties and inherited properties.
and why for c3 can I call c3.town="x"
Because you're simply adding a property. Unless the object is frozen, or sealed you can add any properties you want, any time. You could also add c3.foo = "bar", even if it's not in the prototype or added in the constructor.
and c3.setTown2("x") but not call c3.setTown("x");
Because it's an inherited method, so the object can obtain it traversing the prototype's chain; but you never add setTown to c3 instance, or to any object in its prototype chain.
2: I don't seem to have access to 'prototype' for the c1 (the literal constructor approach), why is this?
Because prototype is a property only for functions, that you can use as constructors. c1 is already an object, so doesn't need to have another object as "prototype". You can use directly c1 as object's prototype to create other object based on it:
var cc1 = Object.create(c1);
That will inherit all the methods and property c1 has, so:
console.log(cc1.name) // "Neil"
console.log(cc1.hasOwnProperty("name")) // false
As we see in the first point.
Hope it helps.

Related

Objects types in Javascript

This is a fairly general question coming from a newbie in the learning phase and is on something I need clarifying.
I'm currently learning about objects and at this point I'm learning about inheritance. At this point in the lesson I've learned a few different ways to create objects but objects using the this keyword seems to have the most function:
function Person(){
this.eyes = 2;
this.ears = 2;
this.arms = 2;
this.hands = 2;
this.feet = 2;
this.legs = 2;
this.species = "Homo sapien";
}
I understand what I might use this for but then there's an object created this way:
var person = new Object();
person.eyes = 2;
person.ears = 2;
person.arms = 2;
person.hands = 2;
person.feet = 2;
person.legs = 2;
person.species = "Homo sapien";
Because I seem to be able to do things with the former that I can't do with the latter, I'm wondering if there's any reason why I wouldn't just use the former method all the time. Can anyone help me out with this? I don't need a long detailed answer (although one would be appreciated). It's just a question I want to get out of my head so that I don't dwell on it.
Preface: If you're not sure what I mean by the word "prototype" below, skip down to below the divider for an explanation, then come back up here to the top of the answer. :-)
Assuming in your first example that you then call Person via new:
var person = new Person();
...then the only difference between that person and the one you'd get using your second example is related to inheritance: The one created via new Person gets assigned the object on Person.prototype as its underlying prototype.
I'm wondering if there's any reason why I wouldn't just use the former method all the time
If you don't need to use the prototype, then using a constructor function could be unnecessarily complicated. Note that your second form could more concisely be written:
var person = {
eyes: 2,
ears: 2,
arms: 2,
hands: 2,
feet: 2,
legs: 2,
species: "Homo sapien"
};
That's called an object initializer: It creates a new object with the properties you see listed. There's never any need to use x = new Object(); if you want a new, blank object, just use x = {};.
When an object is a one-off, creating it directly is often the simplest way to create it.
The key advantage constructor functions have is that they're factories for objects that are fundamentally similar: Have the same set of initial properties, have the same underlying prototype, etc. And the function can accept arguments and use them to outfit the object it's creating in an appropriate way, perhaps do some validation on the construction arguments, etc. That is: They centralize initialization logic.
Constructor functions are not the only way to have function factories. You can also do:
function buildPerson() {
return {
eyes: 2,
ears: 2,
arms: 2,
hands: 2,
feet: 2,
legs: 2,
species: "Homo sapien"
};
}
var person = buildPerson();
And if you want that person to have a prototype (ES5 browsers and higher):
var personPrototype = {
// ...properties for the person prototype...
};
function buildPerson() {
var obj = Object.create(personPrototype);
obj.eyes = 2;
obj.ears = 2;
obj.arms = 2;
obj.hands = 2;
obj.feet = 2;
obj.legs = 2;
obj.species = "Homo sapien";
return obj;
}
var person = buildPerson();
(There's another, more verbose way to define those properties as well.)
JavaScript is amazingly flexible. :-)
"Prototype"
JavaScript uses prototypical inheritance, which is a fancy way of saying that a object A can be "backed" by object B so that if you ask A for a property it doesn't have, the JavaScript engine will look to see if that property exists on B. A quick practical example:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto); // Creates an object backed by the given prototype
Don't worry about Object.create, for now all you need to know is that it creates a new object and assigns its underlying prototype based on the object you pass into it. So obj is backed by proto.
obj doesn't have a name property, but if we do:
console.log(obj.name);
...we see "proto's name". That's because when the JavaScript engine tried to get name's value from obj, it found that obj didn't have a name property, so it looked to obj's prototype, proto. Having found it there, it used the value from proto.
That only happens when getting the value (except in some advanced cases we can ignore for now). When setting a property's value, it gets set on the object you set it on. So:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto); // `obj` is backed by `proto`
console.log(obj.name); // "proto's name"
obj.name = "obj's name";
console.log(obj.name); // "obj's name"
The purpose of prototypes is reuse, and so it's no surprise that an object can be the prototype of several other objects:
var proto = {
name: "proto's name"
};
var a = Object.create(proto); // `a` is backed by `proto`
var b = Object.create(proto); // `b` is also backed by `proto`
console.log(a.name); // "proto's name"
console.log(b.name); // "proto's name"
a.name = "a's name";
console.log(a.name); // "a's name"
console.log(b.name); // "proto's name"
Prototype objects are normal objects; we can change them:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto);
console.log(obj.name); // "proto's name"
proto.name = "updated";
console.log(obj.name); // "updated"
Since obj doesn't have its own name property, each time we access it, the JavaScript engine goes and looks at its prototype.
The new operator automatically assign a prototype to the objects it creates: It uses the object that the function's prototype property has on it. So:
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log("My name is " + this.name);
};
var p = new Person("Fred"); // Creates an object backed by Person.prototype,
// then calls Person with this referring to the
// object
p.sayName(); // "My name is Fred";
Finally: Since prototype objects are normal objects, they also can have prototypes:
var rootProto = {
name: "root proto's name"
};
var middleProto = Object.create(rootProto);
middleProto.middleProp = "middle property";
var obj = Object.create(middleProto);
console.log(obj.name); // "root proto's name"
console.log(obj.middleProp); // "middle property"
For name, the JavaScript engine looks at obj, doesn't see a name property, and so looks at middleProto. It doesn't see a name property there, either, so it looks at rootProto. It finds it there, so it uses it.
Point of confusion: A lot of people are confused by the fact that the property on constructor functions is called prototype and think that somehow it's the prototype of the function. It isn't. It's just a normal property on function objects (functions are objects and can have properties). The only way it's special is that new uses it when you call the function via new. Non-function objects don't have a prototype property, they're prototype isn't a normal property, it's an internal thing. You can get an object's prototype by passing it into Object.getPrototypeOf:
var proto = {/*...*/};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

Assign new property to empty object which has frozen prototype

Why can't I assign new properties to non-frozen object, which has frozen prototype:
Working without Object.freeze:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
Above code works as expected, but I want to make sure that defaults won't be accidentally changed. So I want to freeze my defaults object:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//!!!!!!!!!!!!
Object.freeze(defaults);
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
//TypeError: Cannot assign to read only property 'sections' of #<Object>
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
What I don't get is why can't I assign to specificObject if its prototype is frozen?
//EDIT:
Notice that specific object is not frozen:
'use strict'
//This object will be prototype of next objects
var protoObj = {a: 1, o: {}};
Object.freeze(protoObj);
console.log(Object.isFrozen(protoObj)); //true
var n = Object.create(protoObj);
console.log(Object.isFrozen(n)); //false
What I don't get is why can't I assign to specificObject if its prototype is frozen?
Because property attributes are inherited. Yes, it's odd.
If you freeze an object, it will set the [[writable]] attribute of all data properties to false.
If you assign to an object property, but that property does not exist on the object, it will go and look it up on the prototype - it might be defined as setter there. When this lookup will return and say that there is a property of that name but it is non-writable, your assignment will fail (and throw in strict mode).
What can you do against this?
Use Object.defineProperty instead of assignment, it doesn't check the prototype
or similarly, use the second parameter of Object.create to create the own property
freeze the defaults only after you've assigned to specificObject.
my understanding is that specificObject.sections is pointing to its' prototype which is defaults and it is frozen object. You define a new object {} but you try to assign it to defaults.sections. SpecificObject.sections is pointing exactly there.
If you create new ownProperty on specificObject it will work:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//!!!!!!!!!!!!
Object.freeze(defaults);
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
// this will create new property
Object.defineProperty(specificObject, 'sections',{
enumerable: true,
writable: true,
configurable: true,
value: {}
});
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
explanation:
if you try to access obj.prop = val then javascript looks into obj's own properties, if not found then it looks into obj's prototype own properties. if found there then it /tries to assign val to/ lookup that property. if not found there then it tries to look into obj's prototype's prototype and so on. If prop is not found in the prototype tree then it creates new own property on obj and assigns val.
Therefore if prop is find on prototype and it is frozen you will get type error. Hope it brings some light.:)
EDIT:
as correctly pointed out by #KubaWyrostek specificObj.sections = {} will create new own property of specific Object, does not assign new value to the prototype's property, but it probably does the lookup for the property to check the writability, in that case it will run into frozen object. I didn't know about this before.

Safely inheriting prototypes in JavaScript [duplicate]

This question already has answers here:
Benefits of using `Object.create` for inheritance
(4 answers)
Closed 8 years ago.
Let's say I'm shooting for some basic inheritance in my application, I could achieve this by setting the prototype of my child to the parent.
// Parent "class"
var Car = function(year) {
this.year = year;
};
Car.prototype.drive = function() {
console.log('Vrooom');
};
// Child "class"
var Toyota = function() {
Car.apply(this, arguments);
};
Toyota.prototype = Car.prototype;
var myCar = new Car(2010), myToyota = new Toyota(2010);
myCar.drive(); // Vrooom
myToyota.drive(); // Vrooom
Seems to work, but is obviously bad because if I set a new method on my Toyota.prototype, it will be set on Car's prototype.
Toyota.prototype.stop = function() {
console.log('stooop');
};
myCar.stop(); // stooop <--- bad
myToyota.stop(); // stooop <--- good
To solve this, instead of Toyota.prototype = Car.prototype; I can add an intermediary:
var ctor = function() { };
ctor.prototype = Car.prototype;
Toyota.prototype = new ctor();
Toyota.prototype.stop = function() {
console.log('stooop');
};
myCar.stop(); // throws undefined error <--- good
myToyota.stop(); // stooop <--- good
But I don't understand why this works. ctor creates a new instance with its prototype set to Car's prototype, and then Toyota sets its prototype to that new instance.
But why create an empty object with a prototype that gets referenced by Toyota's prototype?
Why doesn't setting a new method on Toyota set it on Car like it does in the first example?
What if I want several layers of inheritance, it seems like I need to glue them together with a new ctor every time?
But why create an empty object with a prototype that gets referenced
by Toyota's prototype?
Because if you do this: Toyota.prototype = new Car();
Now Toyota's prototype is an instance of Car, which means that in addition to having Car's prototype in the chain, it also has any properties set in the Car constructor itself. Basically you wouldn't want Toyota.prototype to have a property called year like so: Toyota.prototype.year. Because of this it's a lot better to have an empty constructor like so:
var ctor = function() { };
ctor.prototype = Car.prototype;
Toyota.prototype = new ctor();
Now Toyota.prototype has the new ctor() instance as it's prototype, which in turn has Car.prototype in its own chain. This means that instances of Toyota now can execute methods that exist in Car.prototype.
Why doesn't setting a new method on Toyota set it on Car like it does
in the first example?
With this: Toyota.prototype = Car.prototype; you're setting Toyota' prototype to be the same exact object as what Car.prototype contains. Since it is the same object, changing it in one place also changes it everywhere else. This means that objects are passed be reference and not by value, which is another way of saying that when you assign an object to 3 different variables, it is the same object regardless of which variable you use. Strings for example are passed by value. Here is an example with strings:
var str1 = 'alpha';
var str2 = str1;
var str3 = str1;
str2 = 'beta';
// Changing str2 doesn't change the rest.
console.log(str1); //=> "alpha"
console.log(str3); //=> "alpha"
console.log(str2); //=> "beta"
Now compare to objects and their properties;
var obj1 = {name: 'joe doe'};
var obj2 = obj1;
var obj3 = obj1;
console.log(obj1.name); //=> "joe doe"
console.log(obj2.name); //=> "joe doe"
console.log(obj3.name); //=> "joe doe"
obj2.name = 'JOHN SMITH';
console.log(obj1.name); //=> "JOHN SMITH"
console.log(obj2.name); //=> "JOHN SMITH"
console.log(obj3.name); //=> "JOHN SMITH"
What if I want several layers of inheritance...
Here is another way of creating layers of inheritance:
var Car = function(year) {
this.year = year;
};
Car.prototype.drive = function() {
console.log('Vrooom');
};
var Toyota = function() {
Car.apply(this, arguments);
};
// `Object.create` does basically the same thing as what you were doing with `ctor()`
// Check out the documentation for `Object.create` as it takes a 2nd argument too.
Toyota.prototype = Object.create(Car.prototype);
// Create instances
var
myCar = new Car(2010),
myToyota = new Toyota(2010);
// Add method to Toyota's prototype
Toyota.prototype.stop = function() {
console.log('stooop');
};
Let's try it out now:
myToyota.stop(); //=> 'stooop'
myCar.stop(); //=> 'TypeError: undefined is not a function'
myCar.drive(); //=> Vrooom
myToyota.drive(); //=> Vrooom
Your problem is the following line:
Toyota.prototype = Car.prototype;
and then later modifying this object:
Toyota.prototype.stop = function() {
console.log('stooop');
};
because in the first line, you set Toyota.prototype to the exact same object as Car.prototype. This is not a copy, it is a reference to the same object! So as soon as you modify stop on Toyota.prototype, you actually modify both Toyota.prototype and Car.prototype, because it is one and the same.
What you'd really want to do is replacing the first line with:
Toyota.prototype = Object.create(Car);
so that you now have the prototype of Toyota point to the Car function, as it should, instead to Car's own prototype. Congratulations, you've used the prototype chain!
(Note: Using Object.create to do class inheritance is inherently more stable and reliable, because it does not run any code that you might have contained in the Car function, but only sets up the prototype link.)
For further discussion on what is happening here exactly, and why you might be better off not using "class inheritance" in JS at all, you might want to read Chapters 4-6 of You Don't Know JS (objects & prototypes).
On your last question: "What if I want several layers of inheritance, it seems like I need to glue them together with a new ctor every time?" – yes, you'd need to do this, and this is the standard pattern for (fake) classes and inheritance in JavaScript.

Understanding prototypes used in the object constructor function

I understand prototypes can be used to extend properties to their children. However I don't understand why you would want to have a "Object.prototype.property" in the main object constructor class itself?
In the Person constructor why Person.prototype.name = "Nicholas"; VS this.name = "Nicholas";
function Person(){
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name); //"Greg" – from instance
alert(person2.name); //"Nicholas" – from prototype
Setting a prototype property in the constructor is almost certainly an error. The prototype is the shared state of all child objects. The only reason you might want to update the prototype in the constructor is if you are storing shared data. For example, you might increment a counter, or add to a sum. But you would almost never expect for a simple string property like "name" to be set on the prototype within the constructor.
Person.prototype.name = 'Nicholas' and this.name = 'Nicholas' are NOT the same.
Let's see for ourselves:
var PersonA = function () {
this.name = 'Nicholas';
this.species = 'Homo Sapiens'
return this; // optional
};
var PersonB = function () {
return this;
};
PersonB.prototype.name = 'Nicholas';
PersonB.prototype.species = 'Homo Sapiens'
var personA = new PersonA();
console.log(Object.keys(personA)); // logs ["name", "species"]
var personB = new PersonB();
console.log(Object.keys(personB)); // logs []
console.log(personA.species === personB.species); // logs true
Clearly, personA has a 2 keys, "name" and "species"; while personB no keys!.
However, the prototype of personB 2 keys, "name" and "species"
Now, if you create a million objects of PersonA, each such object would have a
"name": "Nicholas" and "species": "Homo Sapiens" key-value pairs.
On the other hand, creating a million objects of PersonB would be much more memory-efficient as each such object would have no key-value pairs at all! At the same time, both "name" and "species" will be available through prototype (prototypal inheritance).
A closer look at refinements:
Lets examine the refinement on an object obj, say obj.foo:
If "foo" is a property of obj, the corresponding value is returned.
Otherwise, the prototype of obj is looked at.
If that prototype has a property "foo", the corresponding value is returned.
Otherwise that prototype's prototype is looked at.
The process continues till we hit Object.prototype.
So in terms of memory, PersonB is superior to PersonA. This is the beauty of prototypal inheritance.
Hope this helps.

Why did assignment affects instance and not prototype attributes?

I joined this meetup every week discussing about the book effective javascript: 68 ways.
In Item 36: Store Instance State Only on Instance Objects, we created the following example to explain it.
function User() {}
User.prototype = {
hobbies: [], // should be instance state!
addHobby: function (x) {
this.hobbies.push(x);
}
};
We instantiate the following users.
boy = new User();
// User {hobbies: Array[0], addHobby: function}
girl = new User();
// User {hobbies: Array[0], addHobby: function}
boy.addHobby("swimming");
girl.addHobby("running");
// undefined
boy.hobbies
// ["swimming", "running"]
girl.hobbies
// ["swimming", "running"]
As you can see, the addHobby function affects hobbies at the prototype level.
Now if I change the entire code to
function User() {}
User.prototype = {
hobbies: [], // should be instance state!
addHobby: function (x) {
newArr = new Array(x);
this.hobbies = this.hobbies.concat(newArr);
}
};
boy = new User();
girl = new User();
boy.addHobby("swimming");
girl.addHobby("running");
boy.hobbies
//["swimming"]
girl.hobbies
//["running"]
We know the reason is because of the assignment. We are looking for a full explanation why this.hobbies = this.hobbies.concat(newArr); assigns to the instance level and not at the prototype level despite in both instances the term this.hobbies is used.
That's just the way the language is defined. From the spec:
The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:
Let baseReference be the result of evaluating MemberExpression.
Let baseValue be GetValue(baseReference).
Let propertyNameReference be the result of evaluating Expression.
Let propertyNameValue be GetValue(propertyNameReference).
Call CheckObjectCoercible(baseValue).
Let propertyNameString be ToString(propertyNameValue).
If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
That Ecma moon language does not include any mention of looking for properties on object prototypes. An l-value member expression always refers to a property on the base object directly involved.
Using "this" you cannot assign anything to the prototype but you can read from it. So when you do this.hobbies = x; you set the property "hobbies" of the current instance rather than that of the prototype, which then hides a prototype-level property of the same name (i.e., boy.hobbies does not longer return the array from the prototype because there is a direct property with this name).
concat() returns a new array rather than a reference to the existing one and hence, you're hiding the prototype-level property "hobbies".
At the next call, the instance-level array "hobbies" is then overwritten by a new one containing the previous values plus the new one.
Whenever you set the value of a property of an object, the property is defined on the object itself, no matter if the property exists in the object's prototype chain or not.
This is described in the specification, section 8.7.2:
4. Else if IsPropertyReference(V), then
(a) If HasPrimitiveBase(V) is false, then let put be the [[Put]] internal method of base, otherwise let put be the special [[Put]] internal method defined below.
(b) Call the put internal method using base as its this value, and passing GetReferencedName(V) for the property name, W for the value, and IsStrictReference(V) for the Throw flag.
The [[Put]] method is described in section 8.12.5, where the important step is:
6. Else, create a named data property named P on object O as follows
(a) Let newDesc be the Property Descriptor
{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.
(b) Call the [[DefineOwnProperty]] internal method of O passing P, newDesc, and Throw as arguments.
If you look closer at the specification you will see though that the assignment will only create the property on the object if the inherited property is not an accessor property.
I.e. the following will actually not create an instance property:
var name = 'foo';
function User() {}
Object.defineProperty(User.prototype, 'name', {
'get': function() { return name;},
'set': function(val) { name = val;}
});
var u1 = new Users();
var u2 = new Users();
u1.name = 'bar';
console.log(u2.name); // shows 'bar'
console.log(u1) // shows 'User {}' instead of 'User {name: 'bar'}'
As for me, this is not the best example of Prototype enheritance.
Thats you example, modified by me:
function User() {
this.hobbies = [];
};
User.prototype = {
addHobby: function (x) {
this.hobbies.push(x);
}
};
boy = new User();
girl = new User();
boy.addHobby("swimming");
girl.addHobby("running");

Categories

Resources