diff --git a/concepts/errors/about.md b/concepts/errors/about.md index b1114329d1..34e3698624 100644 --- a/concepts/errors/about.md +++ b/concepts/errors/about.md @@ -30,7 +30,8 @@ try { } ``` -As any object in JavaScript the Error can be "extended" to create Custom errors. You can use the `instanceof` syntax to check if the error caught is an instance of a particular object. +As with any class in JavaScript, subclasses can inherit from `Error` to create Custom errors by using the `extends` keyword. +The `instanceof` syntax will check if the error caught is an instance of a particular subclass of `Error`. ```javascript class CustomError extends Error {} diff --git a/concepts/errors/introduction.md b/concepts/errors/introduction.md index 34aa51ce76..138afd6610 100644 --- a/concepts/errors/introduction.md +++ b/concepts/errors/introduction.md @@ -19,7 +19,7 @@ Using the `throw` syntax, you can throw an Error. throw new Error('Oops'); ``` -When an Error is thrown, the current execution is stopped and resume in the first catch block of the call stack. +When an `Error` is thrown, the current execution is stopped and resumes in the first catch block of the call stack. ```javascript try { @@ -30,7 +30,8 @@ try { } ``` -As any object in JavaScript the Error can be "extended" to create Custom errors. You can use the `instanceof` syntax to check if the error caught is an instance of a particular object. +As with any class in JavaScript, subclasses can inherit from `Error` to create Custom errors by using the `extends` keyword. +The `instanceof` syntax will check if the error caught is an instance of a particular subclass of `Error`. ```javascript class CustomError extends Error {} diff --git a/concepts/inheritance/.meta/config.json b/concepts/inheritance/.meta/config.json new file mode 100644 index 0000000000..172c43922b --- /dev/null +++ b/concepts/inheritance/.meta/config.json @@ -0,0 +1,5 @@ +{ + "blurb": "Inheritance creates parent-child relationships between classes in JavaScript. Learn how to use inheritance to create objects with shared behavior.", + "authors": ["JakeWitcher"], + "contributors": [] +} diff --git a/concepts/inheritance/about.md b/concepts/inheritance/about.md new file mode 100644 index 0000000000..e75dc4c7a6 --- /dev/null +++ b/concepts/inheritance/about.md @@ -0,0 +1,144 @@ +# About + +Inheritance is a way to create parent-child relationships between classes. +The child class (sometimes referred to as a _subclass_) has access to the behavior and data defined by the parent class (sometimes referred to as a _superclass_). + +```javascript +class Pet { + constructor(name) { + this.name = name; + } + + introduce() { + console.log(`This is my pet, ${this.name}.`); + } +} + +class Dog extends Pet {} + +const dog = new Dog('Otis'); +dog.introduce(); +// => This is my pet, Otis. +``` + +The `extends` keyword in the child class declaration establishes a relationship with the parent class through the [prototype chain][prototype-chain]. + +Objects created by the child's constructor will have the parent class's prototype in their prototype chain, providing access to any methods or data defined by the parent. + +```javascript +const dog = new Dog('Otis'); + +Dog.prototype.isPrototypeOf(dog); // => true +Pet.prototype.isPrototypeOf(dog); // => true +Pet.prototype.isPrototypeOf(Dog.prototype); // => true + +Pet.prototype.hasOwnProperty('introduce'); // => true +Dog.prototype.hasOwnProperty('introduce'); // => false +dog.hasOwnProperty('introduce'); // => false +``` + +## Constructors + +If no constructor function is defined by the child class, the parent constructor function is used. +However, if the child class defines a constructor function of its own, the parent constructor must be explicitly called. +To invoke the parent constructor from within the child constructor's scope, the keyword `super` is used. + +```javascript +class Pet { + constructor(name) { + this.name = name; + } +} + +class Dog extends Pet { + constructor(name, breed) { + super(name); + this.breed = breed; + } +} + +const dog = new Dog('Otis', 'Pug'); +``` + +Because the parent constructor is responsible for initializing a new object and assigning it to `this`, it must be called before `this` is used by the child constructor. + +```javascript +class Dog extends Pet { + constructor(name, breed) { + // using 'this' before calling the parent constructor with 'super' + this.breed = breed; + super(name); + } +} + +const dog = new Dog('Otis', 'Pug'); +// => ReferenceError: Must call super constructor in derived class before accessing 'this'... +``` + +## Defining Methods on the Child Class + +A child class may define behavior of its own in addition to the behavior inherited from the parent. + +This is one of the key reasons for using inheritance; to have specialized child classes with their own unique data and methods that are related through shared methods and data supplied by the parent class. + +```javascript +class Dog extends Pet { + constructor(name, breed) { + super(name); + this.breed = breed; + } + + describe() { + console.log(`${this.name} is a ${this.breed}.`); + } +} + +const dog = new Dog('Otis', 'Pug'); +dog.introduce(); +dog.describe(); +// => 'This is my pet, Otis.' +// => 'Otis is a Pug.' +``` + +## Overriding Methods Inherited From the Parent Class + +A child class can also override the behavior of a method defined by the parent and replace or extend it with behavior defined by the child class. + +```javascript +class Cat extends Pet { + // replacing parent class behavior + introduce() { + console.log(`This is my cat, ${this.name}.`); + } +} + +class Dog extends Pet { + constructor(name, breed) { + super(name); + this.breed = breed; + } + + describe() { + console.log(`${this.name} is a ${this.breed}.`); + } + + // extending parent class behavior + introduce() { + super.introduce(); + this.describe(); + } +} + +const cat = new Cat('Milo'); +cat.introduce(); +// => 'This is my cat, Milo.' + +const dog = new Dog('Otis', 'Pug'); +dog.introduce(); +// => This is my pet, Otis. +// => Otis is a Pug. +``` + +To call a method defined on the parent class from the body of a method with the same name on the child class, the keyword `super` must be used to reference the parent. + +[prototype-chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain diff --git a/concepts/inheritance/introduction.md b/concepts/inheritance/introduction.md new file mode 100644 index 0000000000..19816981b2 --- /dev/null +++ b/concepts/inheritance/introduction.md @@ -0,0 +1,40 @@ +# Introduction + +Inheritance is a way to create parent-child relationships between classes. +The child class (sometimes referred to as a _subclass_) has access to the behavior and data defined by the parent class (sometimes referred to as a _superclass_). + +```javascript +class Pet { + constructor(name) { + this.name = name; + } + + introduce() { + console.log(`This is my pet, ${this.name}.`); + } +} + +class Dog extends Pet {} + +const dog = new Dog('Otis'); +dog.introduce(); +// => This is my pet, Otis. +``` + +The `extends` keyword in the child class declaration establishes a relationship with the parent class through the [prototype chain][prototype-chain]. + +Objects created by the child's constructor will have the parent class's prototype in their prototype chain, providing access to any methods or data defined by the parent. + +```javascript +const dog = new Dog('Otis'); + +Dog.prototype.isPrototypeOf(dog); // => true +Pet.prototype.isPrototypeOf(dog); // => true +Pet.prototype.isPrototypeOf(Dog.prototype); // => true + +Pet.prototype.hasOwnProperty('introduce'); // => true +Dog.prototype.hasOwnProperty('introduce'); // => false +dog.hasOwnProperty('introduce'); // => false +``` + +[prototype-chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain diff --git a/concepts/inheritance/links.json b/concepts/inheritance/links.json new file mode 100644 index 0000000000..f661343963 --- /dev/null +++ b/concepts/inheritance/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance", + "description": "MDN: Inheritance" + }, + { + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain", + "description": "MDN: Inheritance and the Prototype Chain" + }, + { + "url": "https://javascript.info/class-inheritance", + "description": "javascript.info: Class Inheritance" + } +] diff --git a/config.json b/config.json index cdb2d4edec..fa7cc01eaf 100644 --- a/config.json +++ b/config.json @@ -227,7 +227,7 @@ "slug": "factory-sensors", "name": "Factory Sensors", "uuid": "2ccafa38-2802-44c1-8758-7415edefa909", - "concepts": ["errors"], + "concepts": ["errors", "inheritance"], "prerequisites": ["null-undefined", "conditionals"], "status": "beta" }, @@ -1765,6 +1765,11 @@ "uuid": "cbad4d23-a9d8-4370-add2-f4416a4df027", "slug": "type-conversion", "name": "Type Conversion" + }, + { + "uuid": "c890e216-5acb-4fb8-8081-61eb78eabe87", + "slug": "inheritance", + "name": "Inheritance" } ], "key_features": [ diff --git a/exercises/concept/factory-sensors/.docs/introduction.md b/exercises/concept/factory-sensors/.docs/introduction.md index 34aa51ce76..1722a48302 100644 --- a/exercises/concept/factory-sensors/.docs/introduction.md +++ b/exercises/concept/factory-sensors/.docs/introduction.md @@ -1,5 +1,7 @@ # Introduction +## Errors + Errors are useful to report when something is wrong or unexpected in a program or a piece of code. They are javascript objects. @@ -19,7 +21,7 @@ Using the `throw` syntax, you can throw an Error. throw new Error('Oops'); ``` -When an Error is thrown, the current execution is stopped and resume in the first catch block of the call stack. +When an Error is thrown, the current execution is stopped and resumes in the first catch block of the call stack. ```javascript try { @@ -30,7 +32,47 @@ try { } ``` -As any object in JavaScript the Error can be "extended" to create Custom errors. You can use the `instanceof` syntax to check if the error caught is an instance of a particular object. +## Inheritance + +Inheritance is a way to create parent-child relationships between classes. +The child class (sometimes referred to as a _subclass_) has access to the behavior and data defined by the parent class (sometimes referred to as a _superclass_). + +```javascript +class Pet { + constructor(name) { + this.name = name; + } + + introduce() { + console.log(`This is my pet, ${this.name}.`); + } +} + +class Dog extends Pet {} + +const dog = new Dog('Otis'); +dog.introduce(); +// => This is my pet, Otis. +``` + +The `extends` keyword in the child class declaration establishes a relationship with the parent class through the [prototype chain][prototype-chain]. + +Objects created by the child's constructor will have the parent class's prototype in their prototype chain, providing access to any methods or data defined by the parent. + +```javascript +const dog = new Dog('Otis'); + +Dog.prototype.isPrototypeOf(dog); // => true +Pet.prototype.isPrototypeOf(dog); // => true +Pet.prototype.isPrototypeOf(Dog.prototype); // => true + +Pet.prototype.hasOwnProperty('introduce'); // => true +Dog.prototype.hasOwnProperty('introduce'); // => false +dog.hasOwnProperty('introduce'); // => false +``` + +As with any class in JavaScript, subclasses can inherit from `Error` to create Custom errors by using the `extends` keyword. +The `instanceof` syntax will check if the error caught is an instance of a particular subclass of `Error`. ```javascript class CustomError extends Error {} @@ -43,3 +85,5 @@ try { } } ``` + +[prototype-chain]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain diff --git a/exercises/concept/factory-sensors/.meta/design.md b/exercises/concept/factory-sensors/.meta/design.md index 3558ef359c..92ac6fc903 100644 --- a/exercises/concept/factory-sensors/.meta/design.md +++ b/exercises/concept/factory-sensors/.meta/design.md @@ -22,6 +22,7 @@ The goal of this exercise is to teach the student how to handle errors / excepti ## Concepts - `errors` +- `inheritance` ## Prerequisites