- Prototypal Inheritance is not Inheritance -- Inheritance is for class-based languages
- Prototypal Inheritance is completely opposite of regular Inheritance
- When we create an object with Prototypes, the new object links "up" the prototype chain.
- In regular inheritance, we have a "parent" class and the Inheritance flows downward.
- Inheritance is "copy down", Prototypal is "delegate up"
- All OO in JS is an attempt to make Prototype Inheritance work like Class Inheritance
- We should instead consider JS as having Behavior Delegation, which is a design pattern.
- Let's simplify JS "inheritance" into "Behavior Delegation"
- OLOO -- Objects Linked to Other Objects
function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return "I am " + this.me;
};
function Bar(who) {
Foo.call(this, who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = new Bar("b1");
b1.speak(); // alerts "Hello, I am b1."
- The only thing that matters here is the b1 -> Bar.prototype -> Foo.prototype linkage
- So how do we get from here to OLOO?
- Let's take a couple of steps -- pay attention only to b1, Bar.prototype, and Foo.prototype.
- The first step is to get rid of any Class-oriented thinking (i.e. new)
function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return "I am " + this.me;
};
function Bar(who) {
Foo.call(this, who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = Object.create(Bar.prototype);
Bar.call(b1, "b1");
b1.speak();
- Now we use object.create() to link b1 to Bar.prototype. We now have to
callBar with b1 as the "this" property: i.e.Bar.call(b1, "b1"); - We still have b1 -> Bar.prototype -> Foo.prototype
- Now the next step is to get rid of any reference to .prototype because it's confusing
function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return "I am " + this.me;
};
var Bar = Object.create(Foo.prototype);
Bar.init = function(who) {
Foo.call(this, who);
};
Bar.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = Object.create(Bar);
b1.init("b1");
b1.speak();
- Now we just link b1 directly to bar. We use Object.create() to perform all our links.
- We still have b1 -> Bar -> Foo.prototype
- We still need to get rid of all the references to Foo.prototype and the function Foo constructor
var Foo = {
init: function(who) {
this.me = who;
},
identify: function() {
return "I am " + this.me;
}
};
var Bar = Object.create(Foo);
Bar.speak = function() {
alert("Hello, " + this .identify() + ".");
};
var b1 = Object.create(Bar);
b1.init("b1");
b1.speak(); // alert: "Hello, I am b1."
- An example would be Foo as a Utility object with loggers etc that other objects delegate to
-
What if you want to delegate b1 to more than one object?
- There's only one prototype chain.
-
What if you wanted a constructor?
- You could have one. Bar had an "init" function. We just moved it to Foo.
- If you want to have multiple objects with the same method, you have to do manual explicit polymorpishm which is silly
- Instead, you give them different method names like
findUserandfindTaskvs justfind
-
No more constructors?
- If we need to do init tasks, we can add a function to init
- with
newyou were forced to do construction and init at the same time, this way you have flexibility to construct first and init at another time
-
Is there a performance concern because we don't have prototypes anymore?
- This is the exact same as having prototypes, it has the same performance characteristics
- If you have
b1throughb1000, they would each only have themeproperty
-
Are there real world examples of OLOO?
- This is something Kyle invented and he's still trying to convince the world to stop making classes
-
Will you show us Object.create()?
- Yes, in a second :)
-
What's the main contention point?
- The primary push-back is that "Classes are how we were taught to design things"
- Class design is an option, delegation is another option
- Delegation goes with the flow of how JS actually works
-
How does Object.create() work?
if (!Object.create) {
Object.create = function (o) {
function F() {}
F.prototype = o
return new F();
};
}
- How is JavaScript's [[Prototype]] chain not like traditional/classical inheritance?
- It doesn't copy. It "delegates" up rather than copying down.
- What does "behavior delegation" mean and how does it describe object linking in JS?
- A new object delegates up the prototype chain to another object.
- Why is "behavior delegation" as a design pattern a helpful thing? What are the tradeoffs?
- You don't have copies of the functions
- With delegation, we are embracing the fact that objects continue to exist and are dynamically changing
- With classes, it's a snapshot -- once we've made the copy, if the parent changes the childs don't.
- Delegation is more powerful than classes because you can implement classes in delegation but you can't do the reverse
- One of the tradeoffs is that "shadowing" (having methods with the same name) is awkward
- Another tradeoff is that everything is public. You lose all the benefits of encapsulation
95% of the time, we use module pattern because we normally only want a few instances.
- Create a widget and a button as a "parent" and "child"
- 1st, use the prototype style
- 2nd, use the OLOO style