JavaScript “Prototype Chains”


Prototype chains are a mechanism for making objects that resemble other objects.

When you want two objects to have all the same properties (either to save memory or to avoid code duplication), you might decide to copy all the properties over from one to the other. As an alternative, JavaScript provides the option of prototype chains. This makes one object behave as if it has all the same properties of another object.

var orange = { a:1 };
console.log(orange.a);
COPYRIGHT © 2018 CodeStates
var orange = { a:1 };
console.log(orange.a); // 1
// The value found there gets provided to the logging system as the result of the lookup

If we ask for a property that the object does not have, the interpreter acknowledges the failure by providing “undefined” in response to the attempted look up of the “z” property.

var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined

Now imagine that our program called for an object bearing a resemblance to the orange one we already made. To achieve this, we would build a new object and give it all the same values stored at the same keys.

var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined
var blue =        {};

The new object called “blue” is set up to be a replica of orange object.

var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined
var blue = extend({}, orange);

Although the effect of this copy operation on the blue object will last indefinitely, it’s important to remember that copying happens just at the moment during the program’s execution.

COPYRIGHT © 2018 CodeStates

The copying is completed and won’t be repeated. So, if our program modifies orange or blue over time, we’d probably only expect them to have the “a” property in common after the modifications.

var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined
var blue = extend({}, orange);
blue.b = 2;
console.log(blue.a); // 1
console.log(blue.b); // 2
console.log(blue.z); // undefined
var rose = ______________;

Let’s make another replica of the orange object by using a different strategy. The Object.create function can create objects with this lookup delegation feature. When passing our delegated fallback object, it produces a new object that delegates failed lookups to your fallback object.

COPYRIGHT © 2018 CodeStates
var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined
var blue = extend({}, orange);
blue.b = 2;
console.log(blue.a); // 1
console.log(blue.b); // 2
console.log(blue.z); // undefined
var rose = Object.create(orange);
rose.b = 2;

You can still interact with this special object the same way you would any regular object.

COPYRIGHT © 2018 CodeStates

But, when you ask for a property that isn’t available directly, the lookup “falls through” up the chain to the prototype object. Since the prototype object has the property, the lookup ultimately succeeds. Notice that the “similarity” between rose and orange is achieved at the moment of lookup, not as a result of an earlier copying process.

var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined
var blue = extend({}, orange);
blue.b = 2;
console.log(blue.a); // 1
console.log(blue.b); // 2
console.log(blue.z); // undefined
var rose = Object.create(orange);
rose.b = 2;
console.log(rose.a); // 1
console.log(rose.b); // 2
console.log(rose.z); // undefined

For properties that can be found directly on the lower object, the prototype chain is never conducted. Since the key “b” can be found directly within rose, this isn’t considered as a “failed lookup” and the prototype relationship doesn’t come into play. As usual, completely absent properties are reported as missing.

The main difference between the two techniques is in which moment you expect values on orange to influence the other two objects: a single moment of copying or every moment of lookup event. Modifying orange should reveal an interesting difference.

var orange = { a:1 };
console.log(orange.a); // 1
console.log(orange.z); // undefined
var blue = extend({}, orange);
blue.b = 2;
console.log(blue.a); // 1
console.log(blue.b); // 2
console.log(blue.z); // undefined
var rose = Object.create(orange);
rose.b = 2;
console.log(rose.a); // 1
console.log(rose.b); // 2
console.log(rose.z); // undefined
orange.z = 3; 
console.log(blue.z); // undefined
console.log(rose.z); // 3

When we try to log the new property through blue, no property is found. Since the copy operation was one-time, the relationship between the two objects was over immediately. By contrast, when we look for the “z” property through rose, the failed local lookup results in a fail through lookup on the prototype object and the new value appears to be available on orange’s other style of doppleganger, rose.

COPYRIGHT © 2018 CodeStates

Let’s consider this prototype relationship on its own. The orange object has its own failed lookups. There is a top-level object that every JavaScript object eventually delegates to. We call it “the object prototype,” since it provides the shared properties of all objects.

For example, every single object has a .toString method on it (even a new empty object). When you ask an object for its .toString property, you get an access to a function that can do the appropriate work. Once you’ve accessed the function, you can immediately call it and the object you initiated the property lookup on will have appeared to the left of the dot at call time. Thanks to how the parameter this works, the shared function will work as expected even though the toString method was technically stored only in the object prototype.

A number of other useful helper methods are available there as well and it’s a good idea to look up the documentation about each of them. One of the most useful properties is .constructor, which makes it easy to tell which function was used to create a certain object.

COPYRIGHT © 2018 CodeStates

People frequently confuse the object prototype with this constructor function for objects. So, let’s visualize the two in different boxes for a moment. Whenever you ask an object about its .constructor, the object most likely doesn’t have a local .constructor property. So, the prototype chain gets consulted. The .constructor property on the object prototype points to the constructor function for making objects, which produces the object as the result.

COPYRIGHT © 2018 CodeStates

Even though this diagram shows only one of the three object prototype methods residing “outside” the boundaries of the object, this is how all properties actually work. They’re just references to other objects.

COPYRIGHT © 2018 CodeStates

We can put the representation of the object function back into the object prototype box, since we know it’s not actually “contained” there.

COPYRIGHT © 2018 CodeStates

Every value in the diagram is actually an object being stored elsewhere and referenced by the property (even the number objects and the function objects). So, we can remove Object’s highlighting to make the consistency clearer. Unless you take special steps, most new objects you create will delegate to the object prototype.

But, some of the special sorts of objects you create in JavaScript have extra features, above the beyond the basic characteristics of all objects. Arrays, for example, have methods like .indexOf and .slice. Those are stored in another prototype object called “the array prototype.” Since arrays behave differently from objects, it even has its own version of some standard methods like .toString. The array prototype delegates in turn to the object prototype, so that the non-unique aspects of arrays can be inherited from the object constructor and not every method will need to be re-implemented for arrays.

COPYRIGHT © 2018 CodeStates

Notice that both the array prototype and object prototype have .constructorproperties even though one delegates to the other. When querying an array for its .constructor property, the array prototype doesn’t need to delegate any further up the prototype chain to find it. The lookup for .constructor in this example fails on the array instance. But, it doesn’t fail once it reaches the array prototype. A property on an object with the same name as a property further up the prototype chain is said to “mask” the property higher up.

 

SOURCE:  https://medium.com/@hyejunglim/javascript-prototype-chains-cff594f35431

 

Hyejung(Jen) Lim

 

 

Scroll al inicio

Si continuas utilizando este sitio aceptas el uso de cookies. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar