发布时间:2025-12-09 11:52:22 浏览次数:2
At a cliffhanger!
from Object.prototypeFunction.prototypeWerewolf.prototype.howl = function(thing) {console.log('The werewolf howls at the ' + thing + '.');}sadWerewolf.howl('moon');partyWerewolf.howl('bowl of chips'); When we added a property to the constructor's prototype, something unusual happened! How were the instances of that constructor affected? →
The instances immediately had access to the new property, even though they were instantiated before the prototype was set.
When a property is requested from an object, where are the places that the property is searched for?
Object.prototypeIf you add a property directly to an object, it is added to the object itself, not the object's prototype. What's the output of the following code? →
Werewolf.prototype.clothing = 'tattered shirt';console.log(partyWerewolf.clothing);partyWerewolf.clothing = 'backwards cap';console.log(partyWerewolf.clothing);console.log(sadWerewolf.clothing);tattered shirtbackwards captattered shirt Again, when you add a property to an object, that property is added to the object itself…
Let's break down all of the properties of our partyWerewolf object and determine where they came from →
partyWerewolf properties=====from partyWerewolf object-----clothing: backwards cap mood: partying from Werewolf.prototype-----clothing: tattered shirt (masked)howl: (function)from Object-----toString: (function)etc. A common pattern for implementing inheritance is to: →
Object.createUsing our parent constructor, Werewolf
function Werewolf(mood) { this.mood = mood;}Werewolf.prototype.howl = function(thing) {console.log('The werewolf howls at the ' + thing + '.');}Create a constructor for a space werewolf (!!!) by setting its prototype to a new object who's prototype is Werewolf.prototype
function SpaceWerewolf() {}SpaceWerewolf.prototype = Object.create(Werewolf.prototype);This isn't quite complete, though. →
A common pattern for implementing inheritance is to: →
Object.createUsing our parent constructor, Werewolf
function Werewolf(mood) { this.mood = mood;}Werewolf.prototype.howl = function(thing) {console.log('The werewolf howls at the ' + thing + '.');}Create a constructor for a space werewolf (!!!) by setting its prototype to a new object who's prototype is Werewolf.prototype
function SpaceWerewolf() {}SpaceWerewolf.prototype = Object.create(Werewolf.prototype);This isn't quite complete, though. →
In the previous implementation, there's actually some stuff missing when we create a SpaceWerewolf. What's missing from the previous implementation that results in incomplete inheritance? →
mood)?const w = new SpaceWerewolf();console.log(mood) Hm. The constructor, Werewolf, sets the property, mood…
super in Java).callfunction SpaceWerewolf(mood) { Werewolf.call(this, mood);} All object's have a property named constructor. constructor is the function that was used to create the instance's prototype.
const a = [];console.log(a.constructor); // [Function: Array] So we should probably set that on our child constructor's prototype property explicitly so that all objects created from SpaceWerewolf have that as its constructor.
SpaceWerewolf.prototype.constructor = SpaceWerewolf;
function Werewolf(mood) { this.mood = mood;}Werewolf.prototype.howl = function(thing) {console.log('The werewolf howls at the ' + thing + '.');}function SpaceWerewolf(mood) { Werewolf.call(this, mood);}SpaceWerewolf.prototype = Object.create(Werewolf.prototype);SpaceWerewolf.prototype.constructor = SpaceWerewolf;const w = new SpaceWerewolf('in space');console.log(w.mood);console.log(w.constructor); Check out the following example… →
function Monster() {this.scary = true;}Monster.prototype.boo = function() { console.log('Boo!');}function Werewolf(mood) { Monster.call(this);this.mood = mood;}Werewolf.prototype = Object.create(Monster.prototype);Werewolf.prototype.constructor = Werewolf;Werewolf.prototype.howl = function(thing) {console.log('The werewolf howls at the ' + thing + '.');} What would the output be if the following code were run… →
const sadWerewolf = new Werewolf('sad');const partyWerewolf = new Werewolf('partying');partyWerewolf.scary = false;console.log(sadWerewolf.scary);console.log(partyWerewolf.scary);partyWerewolf.boo();truefalseBoo!Some notes on the example:
Monster.prototype as the prototypeconst sadWerewolf = new Werewolf('sad'); sadWerewolfWhat if we only want the properties that were explicitly set on our object, rather than including inherited ones. →
We could use the hasOwnProperty method that every object inherits from Object.prototype!
console.log('party\n-----');for (const p in partyWerewolf) {if (partyWerewolf.hasOwnProperty(p)) {console.log(p + ': ' + partyWerewolf[p]);}}console.log('\n');console.log('sad\n-----');for (const p in sadWerewolf) {if (sadWerewolf.hasOwnProperty(p)) {console.log(p + ': ' + sadWerewolf[p]);}} If you have an object, and you'd like to know what constructor it came from, you can use the instanceof operator.
What do you think the following code will print out? →
console.log(myCar instanceof Car);console.log(myCar instanceof Bike);truefalse(in actuality instance of checks if an object has in its prototype chain the prototype property of a constructor)
These two bits of code both produce a function called HttpRequest! →
ES6 class:
class HttpRequest {}ES5 constructor:
function HttpRequest() {}Both result in the same output when used in the following manner:
const req = new HttpRequest();console.log(HttpRequest);console.log(typeof req.constructor);console.log(req.constructor.name); ES6 style classes allow for a constructor to be defined as follows:
this which represents the instance that is createdclass HttpRequest { constructor(method, url) { this.method = method; this.url = url; }}The above code is mostly the same as this ES5 function that can be used as a constructor:
function HttpRequest(method, url) { this.method = method; this.url = url;}We'll see later that subclass constructors must call super before using this.
In ES5, to add a method to the prototype, we'd have to do something like this:→
function HttpRequest(method, url) { this.method = method; this.url = url;}HttpRequest.prototype.makeRequest = function() { return this.method + ' ' + this.url + ' HTTP/1.1';} In ES6, we can define methods directly in the class definition, and they will show up in the instances' prototype →
class HttpRequest { constructor(method, url) { this.method = method; this.url = url; } makeRequest() { return this.method + ' ' + this.url + ' HTTP/1.1'; }}functionthis, and if the method is called within the context of an instance, then thisrefers to the instanceNote that creating these methods in ES6 style classes is actually just adding to the prototype! →
const req = new HttpRequest('GET', 'http://foo.bar/baz');console.log(req.makeRequest());console.log(Object.getPrototypeOf(req).makeRequest); Use extends to inherit from a class! (read: set up a prototype chain)
class Element { constructor(name) { this.name = name; }}class ImgElement extends Element { // make sure to call super before using this // within subclass constructor(url) { super('img'); this.url = url; }}const img = new ImgElement('http://foo.bar/baz.gif');console.log(img.name);console.log(img.url); In the previous example, super was used to call the base class constructor. →
super must be called in your subclass constructor if…this within your constructorthis properties the way that the superclass wouldsuper must be called before using this within a subclassEvery object in JavaScript links to another object called its [[prototype]]. →
Object.create__proto__ that allows direct access to a [[prototype]], but its use is discouraged)