javascript.info Prototypes, inheritance
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); Rabbit.prototype = {}; alert( rabbit.eats ); let rabbit2 = new Rabbit(); alert(rabbit2.eats);
true undefined // ones created after the reassignment will be affected
let animal = { eat() { this.full = true; } }; let rabbit = { __proto__: animal }; rabbit.eat(); console.log(rabbit.full); console.log(animal.full);
true undefined // this is based on the object before the dot rabbit.eat() only modifies rabbit
The prototype is only used for ____________ properties.
reading
Changing a prototype on the fly with Object.setPrototypeOf or obj.__proto__= is a very ________ operation.
slow
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); alert( rabbit.eats );
true
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); Rabbit.prototype = {}; alert( rabbit.eats );
true // assignment sets [[Prototype]] for new objects but does not affect existing ones
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); delete rabbit.eats; alert( rabbit.eats ); // ?
true // can look onto its prototype where it exists; all delete operations are applied directly to the object and rabbit doesn't even have an eats property
let animal = { jumps: null }; let rabbit = { __proto__: animal, jumps: true }; alert( rabbit.jumps ); // ? (1) delete rabbit.jumps; alert( rabbit.jumps ); // ? (2) delete animal.jumps; alert( rabbit.jumps ); // ? (3)
true null undefined
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); delete Rabbit.prototype.eats; alert( rabbit.eats ); // ?
undefined // property eats is deleted from prototype and doesn't exist anymore
If we modify a native prototype, for instance adding a method to String.prototype, it becomes available to ______________.
all strings
Javascript does not ensure the right _____________ value.
constructor
The default "prototype" is an object with the only property _____________ that points back to the function itself
constructor
function Rabbit() {} Rabbit.prototype = { eats: true }; let rabbit = new Rabbit(); Rabbit.prototype.eats = false; alert( rabbit.eats ); // ?
false // Objects are assigned by reference so visible throughout the other one
No matter where the method is found, whether it be an obejct or its prototype, in a method call, "this" is always the....
object before the dot
Between a prototype and those that inherit from it, methods are shared but the ___________ is not.
object state
We can only inherit from ______ object at a time.
one
Even if we inherit a method from a prototype, we can __________ it.
overwrite
Object.keys() only returns _______ keys
own
In modern programming,t he only case where modifying a native prototype is approved is __________.
polyfilling
To keep the right constructor, we can choose to add/remove properties to the default ___________ rather than overwriting it as a whole.
prototype
Using the __proto__ property to set a prototype
"animal is the prototype of rabbit" or "rabbit prototypically inherits from animal"
Limitations for __proto__
1. References cannot be circular 2. The value can be either an object or null but nothing else.
Prototype
A hidden property that all objects have that is either null or references another object.
Object.create(proto, [descriptors]);
A method used to create an empty object with a given proto as [[Prototype]] and optional property descriptors.
F.prototype proeprty is only used when _________ is called.
new F
In modern engines, performance-wise, there's _____ difference whether we take a property from an object or its prototype.
no
When would this code work? let obj2 = new obj.constructor();
If we do not modify the default "prototype". For instance: function User(name) { this.name = name; } let user = new User('John'); let user2 = new user.constructor('Pete'); alert( user2.name ); // Pete (worked!) This works because User.prototype.constructor == User
When would this code fail? let obj2 = new obj.constructor();
If we overwrite the default "prototype" function User(name) { this.name = name; } User.prototype = {}; // (*) let user = new User('John'); let user2 = new user.constructor('Pete'); alert( user2.name ); // undefined
alert(Object.prototype.__proto__);
null
obj = {} is equivalent to
obj = new Object()
Is "this" affected by prototypes?
No
How can we create an empty object without a prototype (aka a "pure dictionary" object)?
Object.create(null); // will lack any built-in object methods like toString()
Modern methods to get/set a prototype
Object.getPrototypeOf(obj) -> returns [[Prototype]] of obj Object.etPrototypeOf(obj, proto) -> sets [[Prototype]] of obj to proto
There is no more [[Prototype]] in the chain above _______________.
Object.prototype
How do primitive prototypes work?
Primitives are not objects but if we try to access their properties, temporary wrapper objects are created using built-in constructors like String, Number, and Booleans.
When we read a property from object and it's missing, JavaScript automatically takes it from the ______________.
Prototype
function Rabbit(name) { this.name = name; } Rabbit.prototype.sayHi = function() { alert(this.name); }; let rabbit = new Rabbit("Rabbit"); rabbit.sayHi(); Rabbit.prototype.sayHi(); Object.getPrototypeOf(rabbit).sayHi(); rabbit.__proto__.sayHi();
Rabbit undefined undefined undefined // Only the first call has this == rabbit; the others have this equal to Rabbit.prototype so are all undefined
Why are both hamsters full? let hamster = { stomach: [], eat(food) { this.stomach.push(food); } }; let speedy = { __proto__: hamster }; let lazy = { __proto__: hamster }; // This one found the food speedy.eat("apple"); alert( speedy.stomach ); // apple // This one also has it, why? fix please. alert( lazy.stomach ); // apple
The property stomach is not found in either speedy or lazy so JS looks up the prototypal chain to hamster and pushes the value "apple" into the shared stomach. To fix this, change the push() to an assignment: this.stomach = [food] Or, have each hamster have its own stomach.
Setting Rabbit.prototype = animal states the following:
When a "new Rabbit" is created, assign its [[Prototype]] to animal
IF F.prototype is an object, then the new operator uses it to set __________ for the new object.
[[Prototype]]
___proto___ is a historical getter/setter for
[[Prototype]]
F.prototype is not equivalent to ____________.
__prototype__
___proto___ is not the same as the internal [[Prototype]] property, but rather a _____________ for [[Prototype]]
getter/setter
It's generally a bad idea to add methods to native prototypes because prototypes are __________.
global // if two libraries add the same method, one of them overwrites the other
for.. in loops over both own and _________________ keys.
inherited
Almost all key/value-getting methods ignore __________ properties.
inherited (Ex. Object.keys, Object.values, etc only operate on the object itself)
let animal = { eats: true }; let rabbit = { jumps: true, __proto__: animal }; alert(Object.keys(rabbit)); for(let prop in rabbit) alert(prop);
jumps jumps, then eats
If after the creation, F.prototype property changes (F.prototype = <another object>), then new objects ceated by new F will have another object as [[Prototype]] but already existing objects....
keep the old one