JavaScript OOP concepts - Properties - javascript

On MDN they state the following:
Properties are variables contained in the class; every instance of the
object has those properties. Properties should be set in the prototype
property of the class (function) so that inheritance works correctly.
Looking at the sections I've set to bold I assumed this meant:
myClass.prototype.newProperty = ...
However their example shows the following:
function Person(firstName) {
this.firstName = firstName;
console.log('Person instantiated');
}
var person1 = new Person('Alice');
var person2 = new Person('Bob');
// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"
In their example they're adding the property 'firstName' directly to the class/function using 'this'.
Does this mean:
a) That the function declaration is the prototype? I.e. myClass is the prototype which also has a property prototype which by default is set to Object?
b) That using 'this.' in the function declaration does actually add the property to the myClass.prototype
Edit: Updated title

JavaScript doesn't have classes, stop thinking in classes, because that doesn't work with JavaScript (yes, even with the ES6 class syntax, it's just sugar, there aren't actual classes in JavaScript).
By adding the property to the object's prototype, you ensure that it and any other objects with the same prototype will share this property, this means that they'll all have it, but it also mean that if you change it on one, it will change with all of them. Oops.
The creation of a new object with the new keyword is fairly straightforward:
Create an empty object
Make that object prototype the same prototype as the constructor's
Call the constructor with this as the newly created object.
So adding a property to the prototype of an object will have it shared among all instances of the same constructor, while adding it to this in the constructor will have it only on this specific instance. Because it's set in the constructor, it's safe to assume that all instances will have that variable in them, although it won't be shared with all other instances.
When you call a JavaScript property, the engine will look for it in the following fasion:
Look for the property on the object itself (that's this inside of methods of that object)
If not found, look for the property on the object's prototype
If not found, go up the prototype chain and look for it there
So in your Person example, the lookup chain will look like:
this > Person.prototype > Object.prototype
The constructor's will look like this:
this > Person.prototype > Function.prototype > Object.prototype
Person is a function, so its prototype is inherited from Function.prototype, similarly any function is an Object.
So to your specific questions:
The function declaration is not the prototype. See the object creation process above.
No, this applies the property on this instance, while prototype is shared among all instances.

Related

Can instances of a constructor inherit members that are not defined within the prototype bucket?

MDN explains that the instances of a constructor only inherit members within the constructor.prototype property, but not anything outside of it. For example, Object.prototype.watch() will be inherited to its instance, but not Object.keys();.
If I have a constructor as follows:
function Person(name) {
this.name = name;
}
Person.prototype.greeting = function() {
alert("Hi!");
}
the name property is not inside the prototype property, but the greeting() method is. However, if I create an instance as such:
let person1 = new Person("Foo");
person1 is able to access person1.name as well as person1.greeting() both even though the name property is defined outside of the prototype property.
Technically the answer is yes: an instance can inherit from the prototype object property of its constructor, as well as any properties that the prototype object inherits. This is the generalized meaning of the "prototype chain".
In the case of the example given however, the confusion arises in believing name is inherited - it is not.
Objects can have local or "own" properties in addition to inheriting properties from their prototype chain. Ignoring more advanced usage of getters and setters, inherited properties are read only: if you write to them the value written is held in an "own" property created to locally hold the value written - meaning the value written shadows the inherited value without overwriting it in place.
For more information please research how JavaScript inheritance works and in particular what the Object.prototype.hasOwnProperty method does.
The property and name and method greeting both are available to the person1 in different ways.
name is available to person1 because of new operator
greeting is available to person1 because of prototype
When new operator is used it always returns a Object. And object have its own properties. name is the property of Object.

Javascript: Understanding Prototype chain

I created a simple class as follows:
var Class = function() {};
Class.prototype.testObj = {a:2, b:3};
Now if I do console.log(Class.testObj) I get undefined. But if i create instance of that Class as follows:
var instance = new Class();
console.log(instance.testObj)
I get expected output.
In my understanding, all variables are treated as Objects and have prototype property. When some key is not found in the object, prototype chain is traversed to look for the key-value pair. But in case of Class, it is not traversing the prototype chain.
What am I missing? What additional does new keyword do such that property is accessible?
You must be clear that Class() is your constructor, not an instance object. so Class.testObject will return undefined because Class doesn't have that property.
You can think of a prototype as a recipe for an object. Almost every function has a prototype property that is used during the creation of new instances and that prototype is shared among all of the object instances
A constructor is simply a function that is used with new to create an object
When you do this var instance = new Class(); It means you are creating an instance object of Class, hence instance will inherit prototype properties of Class.
Test:
console.log(instance instanceof Class); // => true
console.log(instance.constructor === Class); // => true
console.log(Object.prototype.isPrototypeOf(Class)); // => true
console.log(Class.prototype.isPrototypeOf(instance)); // => true
Whenever you create an object, such as a function, it inherits from the Object constructor, so this
var Class = function() {};
is an object, and it has it's own prototype property that can be accessed with
Class.prototype
and you can create new properties on the prototype object with
Class.prototype.testObj = {a:2, b:3};
if you wanted to access that, you would actually have to do
console.log(Class.prototype.testObj)
as that's where it is, a property added to the prototype property of Class.
When you use the new keyword some magic happens, a whole new object is created (called an instance), and that object inherits from Class.prototype, from the docs
When the code new Class(...) is executed, the following things happen:
A new object is created, inheriting from Class.prototype.
The constructor function Class is called with the specified arguments
and this bound to the newly created object. new Class is equivalent to
new Class(), i.e. if no argument list is specified, Class is called
without arguments.
The object returned by the constructor function becomes the result
of the whole new expression. If the constructor function doesn't
explicitly return an object, the object created in step 1 is used
instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation
process.)
You have misunderstood the relationship between Class and Class.prototype.
Class is a constructor. Strictly speaking, JavaScript does not differentiate between constructors and general purpose functions, but that's not important right now. Class.prototype is the prototype of instances of Class. That is to say, when you instantiate the class - var x = new Class() - Class.prototype is attached to x as a delegate object.
What this means is that lookups to x will propagate up the delegate chain, and reference variables on that prototype instance.
In my understanding, all variables are treated as Objects and have prototype property.
This is incorrect. JavaScript has many primitive types, and only functions have a property named 'prototype'. Prototypical delegates are only attached to reference types (objects, arrays, and functions) when they are created using new with a constructor or the ECMAScript 5 object.create() notation.
Incidentally, Class does have a prototype delegate, as it's an instance of Function(). One instance of a delegate function method is apply().
Simply put, Class is not an instance of Class, it's an instance of Function, so why would it inherit Class.prototype? The first link in Class's prototype chain is Function.prototype.
We can see that if we pick a function from Function.prototype, such as call, it exists on Class.
typeof Class.call; //function
Object instances have their prototype chain setup with their constructor's prototype. Therefore, nnly objects that are instances of Class will have their prototype chain setup with Class.prototype.
You added the object to the prototype,
If you did console.log(Class.prototype), you would see the object.
The new keyword instantiates the object, which brings out properties attached to its prototype as properties of the instantiated object.
Because the newly instantiated object is actually inheriting the prototype of the parent object, not the parent object itself.

Setting function prototype to a new object

I've been seeing this pattern in code recently:
function Person(){
this.name = "Dan";
}
Person.prototype = {
whatAmI: function(){
alert("I am a person")
}
}
On the above object person object, you can only reference the function whatAmI by calling Person.prototype.whatAmI() instead of Person.whatAmI() .
Is there any particular reason that this is done? Tt seems like its becoming popular and I cant see the benifit other than having methonds hidden on the prototype object instead of the Person object.
I understand the basics prototypes in Javascript, and I understand that using Person.prototype.whatAmI is a little unconventional in code instaed of just calling new Person(). However, I'm talking about places where the Person object is returned from another function call, and used as a normal object. Thus, the only way to call whatAmI is via Person.prototype.whatAmI
The purpose of the prototype property on functions is that it determines what prototype is assigned to objects created via the new expression when it's used with that function, e.g.:
var p = new Person();
Now, p's underlying prototype is the object that Person.prototype referred to when the new expression was evaluated, so:
p.whoAmI();
works.
In general, replacing the object on the prototype property isn't a great idea and you should only do it when setting up inheritance hierarchies. Instead, just add to the existing object:
function Person(){
this.name = "Dan";
}
Person.prototype.whoAmI = function(){
alert("I am a person")
};
A bit tangential, but:
You do have to replace the object, though, when setting up hierarchies.
// Base
function Person(name) {
this.name = name;
}
Person.prototype.whoAmI = function() {
alert("I am " + this.name);
};
// Derived
function Employee(name, position) {
Person.call(this, name);
this.position = position;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
// Augmenting the derived prototype
Employee.prototype.whatDoIDo = function() {
alert("I hold the position " + this.position);
};
(That's not meant to be the be-all, end-all of hierarchies, just a quick example.)
whatmI is meant to be called on Person instances, e.g.:
var bob = new Person();
bob.whatAmI();
The prototype property of a constructor has properties that are accessible to all constructed instances of that constructor.
The ECMAScript 5 specification has a pleasantly readable explanation of the language's prototype-based inheritance:
Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties. Objects are created by using constructors in new expressions; for example, new Date(2009,11) creates a new Date object...
Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.
Prototype is actually a built in way in JavaScript for accomplishing inheritance. An object that has already been defined can have methods and properties added to it by accessing it's prototype.
Go right to the authority on the subject and read up. This topic in particular is what makes JavaScript cool.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
There is no specific reason. It depends on what you want.
If the whatAmI function is needed on instances of the type Person, then you define it on the protoype. If you want it on the type, you can do,
Person.whatAmI = function(){
alert("I am a person")
}
They are both valid uses of the language. What you do depends on your application.

__proto__ : function declaration versus object literal

I've just started reading this article and I'm stuck on the first paragraph:
For the code:
var foo = { x: 10, y: 20 };
we have the structure with two explicit own properties and one
implicit proto property, which is the reference to the prototype
of foo:
Figure 1. A basic object with a prototype.
My question...
Why does the diagram show a foo prototype for a basic object literal?
If I create two objects, it shows this isn't the case:-
object one - a function object / constructor function
object two - a basic object literal with key/value pairs like a dictionary
If I use the debugger, it shows that object one does indeed create a One.prototype which also has an Object.prototype further down the chain, but object two does not have a two.prototype, instead it goes straight to the Object.prototype.
Have i misunderstood the proto concept or is the article incorrect by implying object literals have their own prototype?
EDIT:
I've given up reading the article, it's broken English makes a complicated subject more complicated.
The guy in this video answers my question and to sum it up:
every object has a __ proto __
only functions have a prototype
prototype is the template used when using new operator
The __proto__ comes from the constructor's prototype.
In the first case, One is your constructor. You haven't assigned anything to One.prototype, so it defaults to a Object's __proto__ and you get the two levels of inheritance.
If you had added things to that object, they would show up as part of the One prototype.
function One() {
this.x = 4;
this.y = 'hhh';
}
One.prototype.z = 'foobar';
var one = new One();
In the second case, you are creating an object literal which has Object as it's prototype, so you only inherit from the Object prototype. Prototypes are objects themselves, so if you were to add properties to it, like so:
foo.__proto__.z = 'foobar';
You are modifying the instance of Object that is foo's prototype, it doesn't modify Object itself, only that particular instance of it. That is what the article means, by foo's prototype.
I just did a test in V8 and it seems an object literal doesn't have an instance of Object as it's prototype, it has Object's __proto__ itself, so you should not modify foo.__proto__, you would be modifying the underlying Object prototype that all Objects inherit from. If you do wish do modify it, you should create a new instance of Object first to add to:
foo.__proto__ = {};
foo.__proto__.z = 'foobar';
Example:
var x = {};
x.__proto__ = {};
x.__proto__.z = 'foobar';
var y = {};
y.z; // undefined
Object.z; // undefined
vs.
var x = {};
x.__proto__.z = 'foobar';
var y = {};
y.z; // 'foobar'
Object.z; // 'foobar'
In my opinion, it would be better if object literals automatically created a new instance of Object for their __proto__. Then again, there is no real reason in modifying the prototype of an object literal.
Also note that you should not use __proto__ directly, as it is deprecated, and its future replacement is strongly discouraged as well. You should use Object.create for implementing inheritance in Javascript.
There are two interrelated concepts with prototype in JavaScript:
First, there is a prototype property that every JavaScript function has (it is empty by default), and you attach properties and methods on this prototype property when you want to implement inheritance.Note that this prototype property is not enumerable: it is not accessible in a for/in loop. But Firefox, and most versions of Safari and Chrome, have a __ proto__ “pseudo” property (an alternative way) that allows you to access an object’s prototype property. You will likely never use this __ proto__ pseudo property, but know that it exists and it is simply a way to access an object’s prototype property in some browsers.
The prototype property is used primarily for inheritance: you add methods and properties on a function’s prototype property to make those methods and properties available to instances of that function.
The second concept with prototype in JavaScript is the prototype attribute. Think of the prototype attribute as a characteristic of the object; this characteristic tells us the object’s “parent”. In simple terms: An object’s prototype attribute points to the object’s “parent”—the object it inherited its properties from. The prototype attribute is normally referred to as the prototype object, and it is set automatically when you create a new object.To expound on this: Every object inherits properties from some other object, and it is this other object that is the object’s prototype attribute or “parent.” (You can think of the prototype attribute as the lineage or the parent). In the example code above, newObj‘s prototype is PrintStuff.prototype.

Confused about JavaScript prototypal inheritance

In the book "JavaScript the definitive guide 5 edition", section 9.2 Prototypes and Inheritance, I find the following words:
In the previous section, I showed that
the new operator creates a new, empty
object and then invokes a constructor
function as a method of that object.
This is not the complete story,
however. After creating the empty
object, new sets the prototype of that
object. The prototype of an object is
the value of the prototype property of
its constructor function. All
functions have a prototype property
that is automatically created and
initialized when the function is
defined. The initial value of the
prototype property is an object with a
single property. This property is
named constructor and refers back to
the constructor function with which
the prototype is associated. (You
may recall the constructor property
from Chapter 7 ; this is why every
object has a constructor property.)
Any properties you add to this
prototype object will appear to be
properties of objects initialized by
the constructor.
Now, if that is true, how could prototypal inheritance exists? I mean, let's say the prototype object of a constructor function has a constructor property initially. Because the prototype object itself is an object, to determine its constructor we often use prototype_object.constructor. But now the prototype_object already has a constructor property itself, and it points to the constructor function with which the prototype is associated. In this situation how can inheritance exists?
The .constructor property honestly doesn't matter very much, and has very little to do with inheriting from other objects in JavaScript. It's just a convenient handle to an object's constructor.
For example, if you have an instance of something, and you'd like to create another instance of that thing, but you don't have a direct handle on its constructor, you could do something like this:
const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
const car2 = new myCar.constructor();
console.log(car2.constructor); // [Function: Racecar]
It's important to understand that the .constructor property and the class of an object are not synonymous. As you may have already guessed, the .constructor property is dynamic, just like most other things in JavaScript, so it should not be used for anything like type checking.
It's also important to understand that the .constructor property does not mean that something is a subclass of something else. In fact, there is no reliable way to find out if something is a subclass of something else in JavaScript. Because it's a dynamic language, and because there are so many ways to inherit properties from other objects (including copying properties from other objects after instantiation), type-safe subclasses don't exist in JavaScript like they exist in other languages.
The best way to know if something is a compatible type is to feature-test properties. In other words, duck type.
The instanceof operator ignores the .constructor property. Instead, it checks whether or not the constructor's .prototype exists (with an identity check) in the prototype chain of the object.
With manual constructor functions, inheritance can confuse the .constructor property connection (making it refer to the wrong constructor). You can fix it by manually wiring up the connection. For example, the canonical way to do so in ES5 is this:
function Car () {}
console.log(Car.prototype.constructor); // Car
function Racecar () {}
Racecar.prototype = Object.create(Car.prototype);
// To preserve the same relationship we have with the Car
// constructor, we'll need to reassign the .prototype.constructor:
Racecar.prototype.constructor = Racecar;
var myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
ES6 classes do this for you automatically:
// ES6
class Car {}
class Racecar extends Car {}
const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
That said, I'm not a big fan of either constructor functions or ES6 classes, and I generally have little use for the .constructor property. Why? Because factory functions are far more flexible, far more powerful, and they don't have the pitfalls related to constructor functions and class inheritance. See "Factory Functions vs Constructor Functions vs Classes".
Let say, Dog is a Mammal.
function Mammal() {
this.milk = true;
};
function Dog() {
this.bark = true;
}
Dog.prototype = new Mammal;
So prototype of Dog points to an object of Mammal. This Mammal object has a reference to its constructor so when Dog is new, JavaScript see that Dog prototype is a Mammal so Mammal's constructor is called to produce a valid Mammal object (another one) then make it a Dog object using Dog constructor.
From this, the constructor of Dog.prototype is a Mammal (a Mammal Object that has extra fields and functions added) BUT constructor of Dog is Dog. The inheritance exist because the an instance of Dog has a Mammal as a prototype; hence, Dog is a Mammal. When a method is called and JS cannot find it from Dog.prototype, JS look in Mammal.prototype (which is an Object that has extra fields and functions added).
Hope this helps.
Don't worry about the constructor property - it is irrelevant.
Skip those sentences and you might follow it better.
If you are still unsure of your understanding, google for __proto__ - the internal prototype reference on JS objects. It is even exposed to scripts on Firefox and Safari.
A good reference is https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/The_Employee_Example/Object_Properties/Inheriting_Properties
If you have an object obj, it's prototype is obj.prototype and constructor property referring to obj's constructor is obj.prototype.constructor.
For the object obj.prototype the situation is the same. Let's say proto = obj.prototype, then the reference to the constructor of proto would be found at proto.prototype.constructor.
This is the same as obj.prototype.prototype.constructor, so there is no conflict with obj.prototype.constructor.

Categories

Resources