What does it mean to say, default keys in map? - javascript

Here, it says, An Object has a prototype, so there are default keys in the map. However, this can be bypassed using map = Object.create(null).
I could not understanding the meaning of map = Object.create(null).
1) What does it mean to set map.__proto__ to null?
2) In the above paragraph, what does it mean to say, default keys of map?
3) How these default keys are related to Object having a prototype?

In the above paragraph, what does it mean to say, default keys of map?
You can use an object as a string-to-value map. For example:
var map = {};
map["foo"] = "pizza";
map["year"] = 2001;
You probably expect the mapping to be initially empty. That is, for any key value, you expect the expression map[key] to return undefined, because you haven't set any values yet. However, with a normal object, map["toString"] has a value! This contradicts our expectation from the last sentence, where we expected any map[key] value to be undefined. This is what the docs mean by "default keys" -- some keys are already populated with values, even though you didn't set them.
How these default keys are related to Object having a prototype?
This is because objects inherit some properties from Object.prototype. All objects (or almost all Objects) in JavaScript have a prototype. If you ask an object for a property, and the object doesn't have that property, then it will check if its prototype has the value instead. In the toString case, the new object we created with map = {} doesn't have a toString property of its own, but its prototype, Object.prototype, does have a property named toString. Therefore, when you ask an object instance for a property named toString, you get back the toString property from the prototype.
What does it mean to set map.__proto__ to null?
The solution here is to create an object that doesn't have a prototype at all. That is, an object whose prototype is null. We can do this with Object.create(null).
In that case, when we do map = Object.create(null) and then ask for map["toString"] we really do get undefined, because the null-prototype map doesn't have a prototype to get an inherited toString property from.

map = Object.create(null).
means create an empty object which wouldn't even get properties from Object.prototype.
If you tried
Object.getPrototypeOf(map); it will return null.

Related

Why does Object.prototype not set the value of an object?

I was playing around with javascript in my web browser when I noticed something strange.
I defined a class TestClass like this:
class TestClass{};
var testObj=new TestClass();
Object.setPrototypeOf(testObj, null);
When I console.loged testObj, there were no properties.
Here is where I became confused.
typeof testObj returned "object". But when I ran the following:
Object.prototype.testProperty='testing';
testObj didn't have the property testProperty, even though I'd defined it for all objects and according to typeof, testObj was an object.
Why is this happening? Don't all values inherit properties from Object?
This also happens for [[Scopes]] objects. When, in chrome, I console.log a function and I save its [[Scopes]] property as a global variable, typeof returns "object" but the global variable does not have the property testProperty.
Don't all values inherit properties from Object?
No. Most objects inherit from Object.prototype, but some don't - like the Object.prototype object itself. Also objects whose prototype was explicitly set to null, like the testObj one you created in your code or a Object.create(null). Other cases are objects from different realms, which inherit from a different Object.prototype object.

Why in JS can you not set non-functions on prototype

I wasn't sure how to phrase the title but here's an example that just tripped me up big time
myLib.prototype._handlers = {};
myLib.prototype.destroy = function () {
this._handlers = {};
}
I was writing tests when luckily it caught this issue. That destroy method doesn't actually work.
Why does this happen? I thought that properties on the prototype are created new for each new myLib instance, but from writing these tests all new myLib instances have these handlers.
You can set non-functions on the prototype. The issue is that properties on the prototype are shared across all instances of the object. That is usually NOT what you want for a data property, but it is what you want for a function property.
So, instead, you typically initialize data properties in the constructor for the object and that makes them "own" properties which are unique for each instance which is generally what you want.
I thought that properties on the prototype are created new for each
new myLib instance, but from writing these tests all new myLib
instances have these handlers.
The prototype is an object that serves as a lookup mechanism for properties. When you reference var x = obj.prop, Javascript first looks on the obj object itself to see if there is a property named "prop". If there is, that is considered an "own" property and it's value is fetched. If not, then it goes to the prototype object to see if it has an "own" property named "prop". If it does, then it returns that value. If it does not have that named property, then it checks to see if the prototype object has a prototype of its own and if so, it checks that one and so on...
So, the prototype serves as a lookup reference. Nothing new is copied or created. There's just a "reference" to the prototype that can be used for lookup. This is why the prototype is shared among all instances. It was designed this way on purpose for a number of reasons. One reason is that it's storage efficient. There is only one prototype object that all instances share so all those references don't have to be duplicated on every object instance.
When you assign to a property with:
obj.someProp = "foo";
it will only affect an "own" property. It does not affect the prototype. If there was an "own" property on the object named "someProp", then it's value is updated. If there was not, then a new "own" property is created on the actual object instance. If there was a property of this name on the prototype, then that value is now essentially hidden because the Javascript property lookup scheme will find the "own" property first and will use that from then on (as long as it exists).
It may also be important to understand that when you assign a property in your .destroy() method such as:
myLib.prototype._handlers = {};
myLib.prototype.destroy = function () {
this._handlers = {};
}
This does not actually touch the myLib.prototype._handlers value at all when you execute the obj.destroy() method. Instead, this._handlers = {}; makes a new property on the actual instance of the object, an "own" property. Any reference to this._handlers will find the "own" property first and that's what will be used from then on so it may "seem" like it changed the prototype value, but the new "own" property is just masking the prototype value from then on.
I thought that properties on the prototype are created new for each new myLib instance
No. Prototypes don't create anything. Prototypal inheritance is a cascading lookup system where lookups for a property on an object can escalate to prototype ancestors.
Each object has inherited properties and its "own" properties. Only "own" properties exist directly on an instance. Prototype values do not exist directly on the instance, but rather they are accessed when you ask for some property name on an object, and that property does not exist as an own-property.
Setting a property value always sets an own property directly on the object. So, this._handlers = {} sets (and possibly creates) the _handlers property directly on the instance you called the destroy method on. While property access does cascade up the prototype chain to find a property with the correct name, setting a property does not do so.
It's also critical to understand that the this value is set dynamically at function-invocation time, and may vary from call to call. That is, calling instance1.destroy() and instance2.destroy() will have different this values, even if the destroy function is the exact same function object. The only case in which this will be myLib.prototype is if you explicitly call myLib.prototype.destroy().

Is `__proto__` safe to use as a property name for objects created using `Object.create(null)`?

The context of this question is implementing dictionaries that have no restrictions on what keys can be placed in them (and no funny behavior).
Of course, if you use objects which inherit from Object.prototype, you can get funny behavior if you try and set __proto__.
So the question is, if you create an object that doesn't inherit from Object.prototype, is there anything special about the __proto__ property, and is it as safe to use as any other property name? For example, on my browser __proto__ seems to be "unsafe" on "normal" objects, but "safe" on Object.create(null) objects:
var normal = {};
Object.getPrototypeOf(normal) !== Array.prototype
normal['__proto__'] = Array.prototype;
Object.getPrototypeOf(normal) === Array.prototype // prototype **is** changed
var odd = Object.create(null);
Object.getPrototypeOf(odd) === null
odd['__proto__'] = Array.prototype;
Object.getPrototypeOf(odd) === null // prototype **not** changed
To confuse me more, this dictionary library uses Object.create(null), but also mangles the keys by prepending a ~. Does this mean that it is not safe, in general across implementations, to use arbitrary keys in objects created with Object.create(null)?
As I have recently learnt, __proto__ is not in itself a special property; rather the __proto__ property of the Object prototype is, and by extension the __proto__ property of any object ultimately inheriting it from the Obejct prototype. As this is not the case for objects created with Object.create(null), __proto__ is just like any other property for them. (And as the example in the question linked to above shows, this can also be acheived for objects originally inheriting from Object by disconnecting them from the prototype chain with myObejct.__proto__ = null.)

Is there a way to make 'constructor' a valid key in a JS object?

I'm currently making a chat AI that uses markov chains. One of the backend objects is an object that maps a string to any chain that it is a part of, such that:
var words = {}
words['test'] = [ ['this','is','a','test'], ['this','too','tests','things'] ]
Now, I have a problem. 'constructor' is a perfectly valid word, but it appears as though you can't map it as I have described above, as 'constructor' is a property of every object in JS (along with other things, of course). So to my question: is there a way to construct this map?
constructor isn't a property of every object. Though by default every object created from literal syntax will have constructor in its prototype chain. This is because those objects inherit from Object.prototype, which does have that property.
One solution is to use objects that have no prototype chain.
var words = Object.create(null);
words['test'] = [ ['this','is','a','test'], ['this','too','tests','things'] ];
Now there will be no inherited properties to confuse things. This won't work in IE8 and lower though.
Another solution is to use .hasOwnProperty() to see if the constructor property is on the object itself or inherited. If inherited, then it's not the one you want.
if (words.hasOwnProperty("constructor"))
console.log(words.constructor);
If the condition passes, then we know we're not using the inherited property, but rather the object's own property.

How does __proto__ differ from constructor.prototype?

function Gadget(name, color)
{
this.name = name;
this.color = color;
}
Gadget.prototype.rating = 3
var newtoy = new Gadget("webcam", "black")
newtoy.constructor.prototype.constructor.prototype.constructor.prototype
It always returns the object with rating = 3.
But if I do the following:
newtoy.__proto__.__proto__.__proto__
The chain ends up returning null.
Also in Internet Explorer how would I check the null if there is not a __proto__ property?
I've been trying to wrap my head around this recently and finally came up with this "map" that I think sheds full light over the matter
http://i.stack.imgur.com/KFzI3.png
I know I'm not the first one making this up but it was more interesting figuring it out that finding it :-). Anyway, after that I found e.g. this another diagram that I think says basicly the same:
Javascript object layout
The most surprising thing for me was discovering that Object.__proto__ points to Function.prototype, instead of Object.prototype, but I'm sure there's a good reason for that :-)
I paste the code mentioned in the image here as well for if anyone wants to test it. Note that some properties are added to the objects for making easy to know where we are after some jumps:
Object.O1='';
Object.prototype.Op1='';
Function.F1 = '';
Function.prototype.Fp1 = '';
Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';
mycat = new Cat();
o = {};
// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);
constructor is a pre-defined [[DontEnum]] property of the object pointed to by the prototype property of a function object and will initially point to the function object itself.
__proto__ is equivalent to the internal [[Prototype]] property of an object, ie its actual prototype.
When you create an object with the new operator, its internal [[Prototype]] property will be set to the object pointed to by the constructor function's prototype property.
This means that .constructor will evaluate to .__proto__.constructor, ie the constructor function used to create the object, and as we have learned, the protoype property of this function was used to set the object's [[Prototype]].
It follows that .constructor.prototype.constructor is identical to .constructor (as long as these properties haven't been overwritten); see here for a more detailed explanation.
If __proto__ is available, you can walk the actual prototype chain of the object. There's no way to do this in plain ECMAScript3 because JavaScript wasn't designed for deep inheritance hierarchies.
The Prototypal Inheritance in JavaScript is based on __proto__ property in a sense that each object is inheriting the contents of the object referenced by its __proto__ property.
The prototype property is special only for Function objects and only when using new operator to call a Function as constructor. In this case, the created object's __proto__ will be set to constructor's Function.prototype.
This means that adding to Function.prototype will automatically reflect on all objects whose __proto__ is referencing the Function.prototype.
Replacing constructor's Function.prototype with another object will not update __proto__ property for any of the already existing objects.
Note that __proto__ property should not be accessed directly, Object.getPrototypeOf(object) should be used instead.
To answer the first question, I've created a bespoke diagram of __proto__ and prototype references, unfortunately stackoverflow does not allow me to add the image with "less than 10 reputation". Maybe some other time.
[Edit]
The figure uses [[Prototype]] instead of __proto__ because that is how ECMAScript specification refers to internal objects. I hope you can figure everything out.
Here are some hints to help you understand the figure:
red = JavaScript Function constructor and its prototype
violet = JavaScript Object constructor and its prototype
green = user-created objects
(first created using Object constructor or object literal {},
second using user-defined constructor function)
blue = user-defined function and its prototype
(when you create a function, two objects are created in memory:
the function and its prototype)
Note that constructor property does not exist in created objects, but is inherited from the prototype.
Object is Eve, and Function is Adam, Adam (Function) uses his bone (Function.prototype) to create Eve (Object). Then who created Adam (Function)? -- The Inventor of the JavaScript language :-).
According to utsaina's answer, I want to add more useful info.
The most surprising thing for me was discovering that Object.__proto__
points to Function.prototype, instead of Object.prototype, but I'm
sure there's a good reason for that :-)
It should NOT be. Object.__proto__ should NOT point to Object.prototype. Instead, the instance of Object o, o.__proto__ should point to Object.prototype.
(Forgive me for using the terms class and instance in JavaScript, but you know it :-)
I think the class Object itself is an instance of Function, that's why Object.__proto__ === Function.prototype. Therefore: Object is Eve, and Function is Adam, Adam (Function) uses his bone (Function.prototype) to create Eve (Object).
Furthermore, even the class Function itself is an instance of Function itself, that is Function.__proto__ === Function.prototype, that's also why Function === Function.constructor
Further furthermore, the regular class Cat is an instance of Function, that is Cat.__proto__ === Function.prototype.
The reason for the above is, when we create a class in JavaScript, actually, we are just creating a function, which should be an instance of Function. Object and Function are just special, but they are still classes, while Cat is a regular class.
As a matter of factor, in Google Chrome JavaScript engine, the following 4:
Function.prototype
Function.__proto__
Object.__proto__
Cat.__proto__
They are all === (absolutely equal) to the other 3, and their value is function Empty() {}
> Function.prototype
function Empty() {}
> Function.__proto__
function Empty() {}
> Object.__proto__
function Empty() {}
> Cat.__proto__
function Empty() {}
> Function.prototype === Function.__proto__
true
> Function.__proto__ === Object.__proto__
true
> Object.__proto__ === Cat.__proto__
true
OK. Then who creates the special function Empty() {} (Function.prototype)? Think about it :-)
I really don't know why people didn't correct you about where the actual problem in your understanding.
This would make a lot easier for you to spot the problem
So let's see what's going on :
var newtoy = new Gadget("webcam", "black")
newtoy
.constructor //newtoy's constructor function is newtoy ( the function itself)
.prototype // the function has a prototype property.( all functions has)
.constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ? ) ! it is not(!) the constructor function !!! this is where your mess begins. it points back to the constructor function itself ( newtoy function)
.prototype // so again we are at line 3 of this code snippet
.constructor //same as line 4 ...
.prototype
rating = 3
Great , so now let's look at this __proto__
Before that , please remember 2 things regarding __proto__ :
When you create an object with the new operator, its internal [[Prototype]]/proto__ property will be set to the prototype property(1) of its constructor function or "creator" if you like .
Hard coded within JS — : Object.prototype.__proto__ is null.
Let's refer to these 2 points as "bill"
newtoy
.__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`.
.__proto__ // Ok so now our starting point is `Gadget.prototype`. so regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`. Ok .( continuing "bill" ) does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of its `constructor function`"
.__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype ( as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED
Better?
Every functions creates it's prototype.
And when we create an object using that function constructor then the __proto__ property of my object will start pointing to the prototype of that function.
If all those figures were overwhelming, let's take a look what the properties mean.
STH.prototype
When creating a new function, there is an empty object being created in parallel and linked to the function with [[Prototype]] chain. To access this object, we use prototype property of the function.
function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}
Bear in mind that prototype property is only available for functions.
STH.constructor
The prototype object mentioned above has no properties except for one - constructor. This property represents a function that created the prototype object.
var toy = new Gadget();
When creating Gadget function, we created an object like {constructor: Gadget} as well - that is nothing like Gadget.prototype. As constructor refers to a function that created an object prototype, toy.constructor represents Gadget function. We write toy.constructor.prototype and we are getting {constructor: Gadget} again.
Therefore, there's a vicious circle: you can use toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype and it always will be Gadget.prototype.
toy
.constructor // Gadget
.prototype // {constructor: Gadget}
.constructor // Gadget
.prototype // {constructor: Gadget}
// ...
STH.__proto__
While prototypeis a property specific for functions, __proto__ is available for all objects as it lays in Object.prototype. It refers to prototype of a function that can create an object.
[].__proto__ === Array.prototype
// true
({}).__proto === Object.prototype
// true
Here, toy.__proto__ is Gadget.prototype. As Gadget.prototype is an object ({}) and objects are created with Object function (see the example above), we get Object.prototype. This is the higher object in JavaScript and its __proto__ can only indicate null.
toy
.__proto__ // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__ // Object.prototype (topmost object in JS)
.__proto__ // null - Object.prototype is the end of any chain
Short answer: __proto__ is a reference to the prototype property of the constructor that created the object.
Objects in JavaScript
A JavaScript object is a built-in type for a collection of zero or more properties. Properties are containers that hold other objects, primitive values, or functions.
Constructors in JavaScript
Functions are regular objects (which implement [[Call]] in ECMA-262 terms) with the additional capability of being callable but play another role in JavaScript: they become constructors (factories for objects) if invoked via the new operator. Constructors are thus a rough analog to classes in other languages.
Every JavaScript function is actually an instance of the Function built-in function object that has a special property named prototype used to implement prototype-based inheritance and shared properties. Every object created by a constructor function has an implicit reference (called the prototype or __proto__) to the value of its constructor prototype.
The constructor prototype is a sort of blueprint for building objects since every object created by the constructor inherits a reference to its prototype.
The prototype chain
An object specifies its prototype via the internal property [[Prototype]] or __proto__. The prototype relationship between two objects is about inheritance: every object can have another object as its prototype. The prototype may be the null value.
The chain of objects connected by the __proto__ property is called the prototype chain. When a reference is made to a property in an object, that reference is to the property encountered in the first object in the prototype chain that contains a property of that name. The prototype chain behaves as if it were a single object.
Whenever you try to access a property in an object, JavaScript starts the search for it in that object and continues with its prototype, the prototype's prototype and so on until the property is encountered or if __proto__ holds the value null.
This type of inheritance using the prototype chain is often called delegation to avoid confusion with other languages using the class chain.
Almost all objects are instances of Object, because Object.prototype is last in their prototype chain. But Object.prototype is not an instance of Object because Object.prototype.__proto__ holds the value null.
You can also create an object with a null prototype like this:
var dict = Object.create(null);
Such an object is a better map (dictionary) than a literal object, which is why this pattern is sometimes called the dict pattern (dict for dictionary).
Note: literal objects created using {} are instances of Object since ({}).__proto__ is a reference to Object.prototype.
Prototypes in JavaScript are confusing for Everyone
A constructor on any type (Object, String, Array, etc) is initially connected with the Function Object that creates them. Once the object types value/objects are created, only then are they assigned their own prototypes, which is a unique property and object the Functions constructor creates when each value is created. But the prototyopes of all objects/types (Object, String, Array, etc) in JavaScript starting out are all Function.prototype. They all derive from functions and their constructors needed to create instances of objects and primitive values in memory! It is not till their values get created by their function constructors that they get assigned their own unique prototypes, both the "prototyoe" property and the Object prototype they inherit from.
This is what 99% of online web pages on the Internet do not tell you!
For example, the Number (or String Array, Boolean, etc.) type always has a constructor, or Number.constructor, which derives from the Function Object assigned to the "Number" type. This is why "Number" is called an "Constructor". So, its prototype is Function.prototype when you check. Once its function or constructor has built a true Number primitive or type, its assigned its own unique prototype of Number.prototype. Let's prove that below!
Here is a simpler explanation. Below is how most objects in JavaScript inherit starting with null down to the object type:
String < Function < Object < null
Array < Function < Object < null
Object < Function < Object < null
Function < Function < Object < null
Here is proof!
Below I am just asking for the prototype found for each object. Note: Object.prototype.toString.call() just tells us the string name of the prototype:
Object.prototype.toString.call(String);// [object Function]
Object.prototype.toString.call(Array);// [object Function]
Object.prototype.toString.call(Object);// [object Function]
Object.prototype.toString.call(Function);// [object Function]
Object.prototype.toString.call(String.__proto__);// [object Function]
Object.prototype.toString.call(Array.__proto__);// [object Function]
Object.prototype.toString.call(Object.__proto__);// [object Function]
Object.prototype.toString.call(Function.__proto__);// [object Function]
Object.prototype.toString.call(String.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Array.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Object.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(Function.__proto__.__proto__);// [object Object]
Object.prototype.toString.call(String.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Array.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Object.__proto__.__proto__.__proto__);// [object Null]
Object.prototype.toString.call(Function.__proto__.__proto__.__proto__);// [object Null]
Please note that the string "[object Function]" is saying that the "prototype" or parent object for the type was "Function.prototype". So it a representation of the underlying prototype parent objects assigned at each level. Now let's explain this in more depth...
A prototype in JavaScript is a word that means the following:
All Objects in JavaScript ultimately inherit from a series of prototypes or "base classes" that assign their various properties and features through inheritance. This cascades down a tree to the child at the bottom. In JavaScript ALL OBJECTS ultimately inherit from the Object.prototype which is close to the top of that inheritance tree.
The term "prototype" means a special object with properties and methods inherited by child objects
"prototype" is also a special property given to all Objects in JavaScript that assigns a given object as the parent prototype to a child but also grants access to changing the prototype. It controls the actual prototype assigned to a child object, but also acts like a true Class Property in that you can use it to manipulate the prototype of a child object. I do not recommend you do this, but you can modify the original Object.prototype inherited by all object by adding new properties using a simple property addition or adding properties via a Object Literal containing properties:
Object.prototype.myproperty = "Hello World";
Object.prototype.myobjectproperties = {text1: "Hello", text2: "World"};
"prototype" the property is expressed in combination with the Child Object name as "MyObjectType.prototype". This new name is now both a identifier for the parent prototype and also a tool to change it. But it is NOT a reference to the actual prototype object! (That is done below using __proto__). It is assigned to all new objects when created of that type. It is first assigned to the function constructor that built the object, then passed to the object the function constructor creates.
"__proto__" is a reference to the actual prototype object assigned to the child. Its also a property but its a reference. So its used to go up the tree of prototypes objects inherited by a child object and access them and their properties. This example below goes up the tree from an object literal created and ends at the top with "null":
alert({}.__proto__.__proto__);// null
Weirdness in Prototype
So, in JavaScript inheritance, everything starts with a Function type! Why is that? Its because you cannot create any of the object "types" (Object, Array, Function, String, etc.) without a Function. And when you do, they still get constructed from a "constructor" called somewhere in a function. A Function and its constructor is what not only creates new objects from types, but also assigns the "prototype" property, the "__proto__" property, and the actual tree of inherited prototypes or objects the child object will use.
There are two states of objects in JavaScript, the "types" and the actual instantiated Objects. That is why "Object" is not the same as a created Object as "const x = {}". And that is why the "type" starts out with a different inheritance or prototypes from its final one.
Check this out!
// The Array type has a prototype of "Function.prototype"
alert(Object.prototype.toString.call(Array));// [object Function]
// But an instance of an Array object has a NEW prototype of "Array.prototype" that the function prototype's constructor created for the object!
const myarray = [];
alert(Object.prototype.toString.call(myarray));// [object Array]
So what happened?
It turns out the FUNCTION CONSTRUCTOR creates and assigns the final prototype when the object is created. But that custom prototype can be modified both before and after the array object is created with many more properties, objects, etc. So the final assigned prototype is set by the constructor of the Function object which as shown above was the Array types initial prototype.
So realize, the Function.prototype is the primary prototype of all Object types in JavaScript! It lies underneath all objects, but is a tool to creating the final instantiated object that is assigned its own prototype when created. Note that the "Array.prototype" has a parent prototype of Object.prototype who has a parent of "null". So the Object.prototype remains the top parent inherited by all these objects. But in the creation of them the constructor changes the immediate parent of all child objects when new objects get created.
Note that the Function.prototype gets many of its features from its own Object.prototype it too inherits. The prototype it builds for your created objects are also made from this parent prototype. So in the end. the Object.prototype provides the goodies needed for Function types and all types to get created and manage the prototype assigned to them. Just remember Function like Object is a special pre-built type with special tools and features needed to create all types of objects!
Last test....lets see how prototype works for CUSTOM OBJECTS we create. The example below proves that the function constructor (part of the Function.prototype) assigns the "prototype" property to the created objects BUT can be customized with various properties and methods before or after being assigned to the objects prototype of MyCustomObject.prototype. This shows that the final prototype of your object need not be a static copy of the Object.prototype's inherited properties, but can be something you create that is entirely new!
let newPet;
function Pet() {
this.fourlegs = true;
}
var Cat = {
type : "cat"
}
var Dog = {
type : "dog"
}
// We can see the prototype our constructor created for us
// and modify it as we like! Here we assigned it to an object
// which only means the prototype will merge "Cat" object's
// properties into the Pet.prototype.
Pet.prototype = Cat;
newPet = new Pet();
alert(newPet.type);// cat - inherited the Cat Object's properties in the prototype
Pet.prototype = Dog;
newPet = new Pet();
alert(newPet.type);// dog - inherited the Dog Object's properties in the prototype
alert(newPet.fourlegs);// true - this shows, even though you replace prototype, it ADDs the new types but does NOT erase the existing object properties! This must mean "prototype" is dynamically additive and rebuilt until the final "Pet" prototype is complete.
// Now change the "Pet.prototype" so all new objects have a new property.
Pet.prototype.furcolor = "white";
newPet = new Pet();
alert(newPet.furcolor);// "white"
// So you can see the "Pet.prototype" is dynamic, something you can tell the function constructor to modify!

Categories

Resources