freeCodeCamp / CurriculumExpansion

Creative Commons Attribution Share Alike 4.0 International
314 stars 104 forks source link

Object Oriented Programming Challenges #15

Closed QuincyLarson closed 8 years ago

QuincyLarson commented 8 years ago

@utsab is in charge of coordinating the expansion of these challenges, but he needs your help.

For each challenge, please reply to this GitHub issue with:

  1. Challenge description text
  2. Test suite (using the assert method)
  3. The seed code, which is pre-populated in the editor at the beginning of the challenge
  4. A working solution that makes all tests pass

Here are the challenges we have currently planned (these can be further expanded):

Objects

Constructors

Prototypes

Inheritance

Other

Here are the challenges as we originally discussed for archival purposes:

  • Declare JavaScript objects as variables #old
  • Constructors
    • Construct JavaScript objects with functions #old
    • Make instances of objects with constructor functions #old
    • Use instanceof to show the type of an object created with a constructor
    • constructor property of an instance also shows the type of an object
    • Make unique objects by passing in parameters to constructor #old
  • More on this
    • Every function gets a variable this ==> context in which the function was called. Illustrate with exercise.
    • this can refer to the global context. Illustrate with exercise
    • this can refer to a specific object. Illustrate with exercise
    • Explicitly set "this" with the "call", "apply", "bind" methods
    • use strict
  • Prototypes
    • Convert constructor-defined methods, "setGear" and "getGear" to prototype methods. (Explain that two "Bike" instances have the exact same method "setGear" ==> duplicate code ==> prototypes can help eliminate the duplicate code.)
    • Properties defined on prototype are available to all instances. Illustrate with exercise.
    • prototype properties vs. "own" properties
    • Iterate over all properties of an object
    • Iterate over all "own" properties of an object (using hasOwnProperty)
    • Iterate over all prototype properties of an object
    • Is the "constructor" property an "own" property or prototype property? Find out.
    • If instance sets its "own" property, it overrides the prototype's property
  • Prototypes with Constructors
    • Every object has a prototype property, including functions. A constructor function has its own prototype property. Illustrate with exercise.
    • When you create an object using new, the constructor's prototype property is assigned to the object instance's prototype. Exercise ==> print out the instance's "prototype" property
    • Changing a prototype affects all instances
    • Modify a built-in object's prototype, like Array. (Explain why this is not a good idea in production).
    • The constructor's prototype property is created with a "constructor" property equal to the function.
  • Inheritance
    • Objects inherit behavior from other objects via prototype chaining. A prototype chain occurs when one object's prototype is set to another object. Since the prototype itself is an object, it has its own prototype.
    • Objects automatically inherit from Object
    • Introduce concepts subtype and supertype
    • Use instanceof to show that an object is an instance of subtype and supertype
    • Show example where the subtype sets its prototype equal to an instance of the supertype
    • Show that you have to manually set the constructor property to the subtype
    • Calling supertype methods ===> use [SuperTypeName].call and pass in this
    • The obj.prototype is not obj's prototype.
  • Encapsulation (Data hiding)
    • Module pattern for creating private members ===> Immediately invoked function expression (IIFE)
    • Closure
    • Modules are great for single objects. Similar pattern for constructed objects. Reuse "Make object properties private" to show how to make private members within a constructor. #old
    • The underscore before name convention
  • Other
    • Prototypal chaining is not the only way to inherit behavior. ===> mixins
    • Various exercises to manipulate Arrays and Strings #old
utsab commented 8 years ago

I'm willing to take this on as the project owner.

QuincyLarson commented 8 years ago

@utsab awesome! Yes - we need to expand this. First things first, could you create a list of challenge titles? OOP is probably complicated enough that we could have 20 or 30 challenges associated with it.

QuincyLarson commented 8 years ago

@utsab I've promoted you to topic owner.

utsab commented 8 years ago

@QuincyLarson yes, I'll compile a list of challenge titles. I'll try to have this done by Wednesday.

utsab commented 8 years ago

Here's a 1st draft of the topics for OOJS. (The pre-existing challenges are marked with hash tag #old):

Constructors

More on "this"

Prototypes

Prototypes with Constructors

Inheritance

Encapsulation (Data hiding)

Other

Looking forward to hearing your feedback @QuincyLarson and anyone else who would like to discuss.

alayek commented 8 years ago

@utsab I am interested! It's midday in India now, and maybe we can have a call tonight? I will also update the list above which started this thread, with your list.

You can reach me via gitter

utsab commented 8 years ago

@alayek, great! Glad to have your help on this. I messaged you on gitter about setting up a time to chat.

QuincyLarson commented 8 years ago

@utsab Thanks for your patience with my slow response.

This is an excellent list of OOP concepts! I am so excited about this. We will finally give OOP the level of detail it deserves.

Let me know if I can be of any help with designing these challenges, their descriptions, and tests. I will look forward to seeing them here as you have time to add them :)

user512 commented 8 years ago

@utsab Thanks for the call. I will be working on Prototypes and Prototypes with Constructors as discussed.

venture-vin commented 8 years ago

@utsab great talking with you! I will take on Mixins and Encapsulation (Data hiding). Will post final solutions after the team review :)

femmestem commented 8 years ago

@utsab Great talk, thanks for onboarding me. As discussed, I will be covering Inheritance.

alookatommorow commented 8 years ago

@utsab Thanks for chatting, glad to be contributing! I am going to cover Constructors.

arielsilvestri commented 8 years ago

@utsab Great to be helping! We made a bit of a change to the curriculum and created an Objects section, which I'll be working on.

arielsilvestri commented 8 years ago

Hey Quincy! I'll be posting my challenges now. We went ahead and made a basic Objects section that we'll need to update the original curriculum list to include.

Challenge Name: Introduction to Objects

Challenge

Create a basic JavaScript object.

Challenge Description

Think about things we encounter in our everyday life, like cars, shops, and birds. These are all objects: tangible things we can observe and interact with.

What are some qualities of these objects? A car has wheels. Shops sell items. Birds have wings. These qualities, or properties, define what makes up an object. It's important to note that cars might all have wheels, but not all cars will have the same number of wheels.

We can use objects in JavaScript to model real-world objects, endowing them with properties and behavior just like their real-world counterparts. We’ll use the previous concepts to create a “duck” object:

var duck = {
  name: "Aflac",
  numLegs: 2
} 

We created a “duck” object with two property/value pairs: a name of Aflac and a numLegs of 2.

Instructions

Create a “dog” object with name and numLegs properties, and set them to a string and a number, respectively.

Challenge Seed

var dog = {
  //Your code here
}

Challenge Tests

Test to verify that the dog object is defined. assert(typeof(dog) === “object”), ‘message: Dog should be an object.’;

Test to verify that the dog object has name and numLegs properties. assert(typeof(dog.name) === ‘string’), ‘message: dog.name should be a string; assert(typeof(dog.numLegs) === ‘number’), ‘message: dog.numLegs should be a number;

Challenge Solution

var dog = {
  name: //string,
  numLegs: //number
}
arielsilvestri commented 8 years ago

Challenge Name: Accessing Properties on Objects

Challenge

Use dot notation to access object’s properties.

Challenge Description

Great job on defining that “dog” object. Now that we have created an object, let's talk about accessing some of these properties!

It's very simple to access the values of a property on an object. See the following example:

var duck = {
  name: "Aflac",
  numLegs: 2
} 

console.log(duck.name)
//This will print "Aflac" to the console. 

By using our object name, duck, along with the property whose value we want to utilize, color, we access the property of your object.

Instructions

Print the properties of the Dog object below to your console.

Challenge Seed

var dog = {
  name: “Spot”,
  numLegs: 4
}

//Add your two console calls here.

Challenge Tests

Test to see that the Dog’s name prints to the console. assert(console.log(dog.name) === “Spot”), ‘message: console.log(dog.name) should print out “Spot”

Test to see that the Dog’s numLegs prints to the console. assert(console.log(dog.numLegs) === 4), ‘message: console.log(dog.numLegs) should print out the number 4.’

Challenge Solution

var dog = {
  name: “Spot”,
  numLegs: 4
}

console.log(dog.name);
console.log(dog.numLegs);
arielsilvestri commented 8 years ago

Challenge Name: JavaScript Object Methods

Challenge

Create a method on an object.

Challenge description

Now that we know how to create an object and access its properties, let's explore a special property of objects. Namely, we will talk about adding a method to our existing objects!

Methods are properties that are functions. We can do all sorts of things with these methods. Let's look at the previous duck example, and add a method:

var duck = {
  name: "Aflac",
  numLegs: 2
  sayName: function() {return "The name of this duck is " + duck.name + "."}
} 

duck.sayName();
//This will return "The name of this duck is Aflac."

As you can see above, we added the sayName method, which is a function that we can call to return a sentence telling us the color of the duck. This is a straightforward method of adding a method to an object in JavaScript.

Notice that we access the name of the duck in the method. We'll get back to that in the next lesson, but for now, this is the way we will insert that value into the string.

Instructions

In the following exercise, draw upon the previous “dog” object you created, and give it a method sayLegs. This method should return a sentence that says "This dog has 4 legs."

Challenge Seed

var dog = {
  name: “Spot”,
  numLegs: 4
  //Add your method here.
}

dog.sayLegs();

Challenge Tests

Test to see if the Dog object has a sayLegs method that returns the desired string. assert(typeof(dog.sayLegs() === ‘function’), ‘message: dog.sayLegs() should be a function.’ assert(dog.sayLegs() === “This dog has 4 legs.”), ‘message: dog.sayLegs() should return the desired string.’

Challenge Solution

var dog = {
  name: “Spot”,
  numLegs: 4
  sayLegs: function() {return "This dog has " + dog.legs + " legs."}
}

dog.sayLegs();
arielsilvestri commented 8 years ago

Challenge Name: Introducing "This"

Challenge

Make code more reusable with “this”.

Challenge Description

We are going to look at our sayName method from the previous example

  sayName: function() {return "The name of this duck is " + duck.name + "."}

Notice how we are referencing the variable name of our object, duck inside the sayName method in order to access the name property. While this is a totally valid way to access our object's property, there is a bit of a pitfall here.

What if the variable name of our object changes? What if, instead of a duck, it's a mallard now? Well, we would have to change duck.name to mallard.name. In this small example, that's fine, but what happens when we have an object that makes many references to its properties throughout its methods? Now the process gets much more complex!

There's a way to avoid that all. Introducing...this:

var duck = {
  name: "Aflac",
  numLegs: 2,
  sayName: function() {return "The name of this duck is " + this.name + "."}
} 

This is a very robust topic that would be a great idea to research more deeply. For now, understand that this, in the current context, refers to the object that our method is associated with: duck.

Now, if we changed our object's name to mallard, we don't have to find all our references to duck in our code. We've made our code more reusable and easy to read.

Instructions

Modify the dog.sayLegs method to remove any references to dog. It should follows the same code style as the duck object.

Challenge Seed


var duck = {
  name: "Aflac",
  numLegs: 2,
  sayName: function() {return "The name of this duck is " + this.name + "."}
}; 

// Modify code below this line. 

var dog = {
  name: “Spot”,
  numLegs: 4,
  sayLegs: function() {return "This dog has " + dog.numLegs + " legs."}
}; 

dog.sayLegs();

Challenge Tests

Test to see if dog.sayLegs() still returns the desired string. assert(dog.sayLegs() === “This dog has 4 legs.”), ‘message: dog.sayLegs() should return the desired string.’

Challenge Solution

var dog = {
  name: “Spot”,
  numLegs: 4,
  sayLegs: function() {return "This dog has " + this.numLegs + " legs."}
}

dog.sayLegs();
venture-vin commented 8 years ago

Challenge - 1

Use a Mixin to add common behavior between unrelated objects

What is a Mixin

As you have previously seen you can share behaviour through inheritance, but there are cases when inheritance is not the best solution. Inheritance does not work well for unrelated objects like Bird and Airplane. They can both fly, but a Bird is not a type of Airplane and vice versa.

For unrelated objects, it's better to use mixins. A mixin allows a collection of functions to be used by other objects.

var flyMixin = function(obj) {
    obj.fly = function() {
        console.log("Flying, wooosh!")
    }
}

The flyMixin takes any object and gives it the fly method.

var bird = {
    name: “Donald”,
    numLegs: 2,  
}

var plane = {
    model: “777”,
    numPassengers: 524 
}

flyMixin(bird); 
flyMixin(plane); 

Here bird and plane are passed into flyMixin, which then assigns the fly function to each object. Now bird and plane can both fly.

bird.fly(); //results in output on the screen: Flying, wooosh!
plane.fly(); //results in output on the screen: Flying, wooosh!

Note how the mixin allows for the same fly method to be reused by completely unrelated objects bird and plane.

Instructions

Create a mixin named glideMixin’ that defines a method namedglide. Use theglideMixinto give bothbirdandboatthe ability toglide`.

Challenge Seed

var bird = {
    name: ‘Donald’, 
    numLegs: 2,  
} 

var boat = {
    name: 'Warrior', 
    type: 'race-boat',  
}

// Only add code below this line.

Challenge Tests

assert(/var glideMixin = function(.+)/.test(code), ‘message: Please use the `var glideMixin` and set it equal to an anonymous function’
assert(typeof glideMixin === "function", ‘message: `glideMixin` should follow the proper structure of a function)
assert(/glideMixin\(.+\)/.test(code), ‘message: Don’t forget to pass the object to your mixin, to give it access to `.glide` method’

Challenge Solution


var glideMixin = function(obj) {
    obj.glide = function() {
        console.log("Gliding on the water")
    }
}

glideMixin(bird); 
glideMixin(boat); 
venture-vin commented 8 years ago

Challenge - 2

Use closure to protect properties within an object from being modified externally.

Introduction to Private Properties

In the previous challenge, bird had a public property name. We say it is public because it can be changed outside of the context of bird.

bird.name = "Duffy"

Any part of your code can therefore easily change the name of bird to any value. Think about things like passwords and bank accounts being easily changeable by any part of your codebase. That could be catastrophic.

The simplest way to make properties private is by creating a var within the constructor function. In this way the private properties can only be accessed and changed by privileged methods within the constructor.

function Bird() { 
  var hatchedEgg = 10; // private property

  this.getHatchedEggCount = function() { //publicly available method that a bird object can use
  return hatchedEgg();  
  }
}

ducky = new Bird(); 
ducky.getHatchedEggCount() //returns 10

Here getHachedEggCount is a privileged method, because it has access to the private variable hatchedEgg. This is possible because hatchedEgg is declared in the same context as getHatchedEggCount. In javascript a function always has access to the context in which it was created. This is called closure.

Instructions

Change the function in the text editor to make the weight parameter private.

Challenge Seed

// rewrite the function below
function Bird() {
  this.weight = 15; 
}

Challenge Tests

assert(/var weight/.test(code), 'message: Please use the `var` before the weight to make it private'
assert(/function handleWeight\(\) {/.test(code), 'message: Please make sure to create a named function within your Bird object' 
assert(/return weight;/.test(code), 'message: Please remember to have a return statement for your private weight variable'
assert(/this.getWeight = function\(\) {/.test(code), 'message: Make sure to have a public method that an instance of your `Bird` can call on'

Challenge Solution

function Bird() { 
  var weight = 15; 
  function handleWeight() {
    return weight; 
  }
  this.getWeight = function() {
    return handleWeight();  
  }
}

Resources

https://curiosity-driven.org/private-properties-in-javascript http://javascript.crockford.com/private.html

venture-vin commented 8 years ago

Challenge - 3

Understand the immediately invoked function Expression (IIFE)

Challenge Description

A common pattern in javascript is to execute a function as soon as it is declared:

  (function () {
    console.log("Chirp, chirp!")
  })(); // this is the anonymous function expression that executes right away
// Outputs "Chirp, chirp" immediately

Note that the function has no name and is not stored in a variable. The two parentheses () at the end of the function expression cause it to be immediately executed or invoked. This pattern is known as an immediately invoked function expression or IIFE.

Instructions

Rewrite the function in the text editor to be an immediately invoked function expression (IIFE).

Challenge Seed

function makeNest() {
    console.log("A cozy nest is ready"); 
}

makeNest(); 

Challenge Tests

assert(/\(function\(\) {/.test(code), 'message: Make sure your new function is anonymous'
assert(/}\)\(\)/.test(code), 'message: Don’t forget to have double parentheses at the end of your function expression'

Challenge Solution

(function() {
    console.log("A cozy nest is ready")
})(); 
venture-vin commented 8 years ago

Challenge - 4

Use an IIFE to create a module

Challenge Description

An immediately invoked function expression (IIFE) is often used to group related functionality into a single object or module. For example, in a previous section, we defined two mixins:

function glideMixin(obj) {
      obj.glide = function() {
        console.log("Gliding on the water")
      }
}

function flyMixin(obj) {
      obj.fly = function() {
        console.log("Flying, wooosh!")
      }
}

We can group these mixins into a module as follows:

var motionModule = (function () {
  return {
    glideMixin: function (obj) {
      obj.glide = function() {
        console.log("Gliding on the water")
      }
    }, 
    flyMixin: function(obj) {
      obj.fly = function() {
        console.log("Flying, wooosh!")
      }
    }
  }
}) (); // The two parentheses cause the function to be immediately invoked

Note that we have an immediately invoked function expression (IIFE) whose sole purpose is to return an object. motionModule is this returned object. This returned object contains all of the mixin behaviors as properties on the object.

The advantage of the module pattern is that all of our motion behaviors can be packaged into a single object which can then be used by other parts of your code. Here we show a sample invocation:

motionModule.glideMixin(duck); 
duck.glide(); 

Instructions

Create a module named funModule to wrap the two mixins isCuteMixin and singMixin.

Challenge Seed

var isCuteMxin = function(obj) {
    obj.isCute = function() {
        return true
    }
}
var singMixin = function(obj) {
    obj.sing = function() {
        console.log("Singing to an awesome tune"); 
    }
}

Challenge Tests

assert(typeof funModule !== undefined, "message: <code>funModule</code> should be defined"); 
assert(funModule.isCuteMixin !== undefined, "message: <code>funModule.isCuteMixin</code> should be defined"); 
assert(funModule.singMixin !== undefined, "message: <code>funModule.singMixin</code> should be defined"); 

Challenge Solution

var funModule = (function () {
  return {
   isCuteMixin: function (obj) {
      obj.isCute = function() {
        return true
      }
    }, 
   singMixin: function(obj) {
      obj.sing = function() {
        console.log("Singing to an awesome tune")
      }
    }
  }
}) ();
alayek commented 8 years ago

@venture-vin @silvestrijonathan great work!

Could you please point which of the items in the roadmap these challenges point to? I will update the roadmap

venture-vin commented 8 years ago

@alayek - no problem did you want that in the beginning of each comment, and did you want general topics or the more specific topics? (Mine are Mixin & Data Encapsulation)

alayek commented 8 years ago

If you are adding challenges that are not mentioned in the roadmap, that's still fine. Just copy the roadmap and check off the item you are taking. Or copy it, add the item where it would fit in, and check it off.

I have updated one of the challenges you have submitted.

You wanted some help with how to introduce Closures without going into concepts of garbage collector etc. We can discuss if you are available.

arielsilvestri commented 8 years ago

@alayek, I'll go back and add those in after we discuss how we'll be adding them to the roadmap. Thanks!

femmestem commented 8 years ago

Inheritance

Challenge 3: Set the Child's Prototype to an Instance of the Parent

Updated: 08/24/16

Challenge

Challenge: Set the Child's Prototype to an Instance of the Parent

Challenge Description In the previous challenge we showed step 1 for inheriting behavior from the supertype (or parent) Animal: making a new instance of Animal.

In this challenge, we cover the next step: set the prototype of the subtype (or child) -- in this case, Bird -- to be an instance of Animal.

Bird.prototype = Object.create(Animal.prototype);

What does that do for us? Remember that the prototype is like the "recipe" for creating an object. In a way, we are saying that the recipe for Bird includes an instance of Animal as a key ingredient.

var duck = new Bird("Donald"); 
duck.eat(); // prints "nom nom nom"

duck inherits all of Animal's properties including the eat method.

Instructions

Modify the code so that instances of Dog inherit from Animal.

Challenge Seed

function Animal() {

};

Animal.prototype = {
    constructor: Animal, 
    eat: function() {
        console.log("nom nom nom");
    }
}

function Dog() {

};

//
// Add code here
//

var beagle = new Dog();

beagle.eat();  //Should print "nom nom nom"

Challenge Tests assert(Animal.prototype.isPrototypeOf(Dog.prototype), 'message: Dog.prototype should be an instance of Animal);

Challenge Solution

function Animal() {};
function Dog() {};

Animal.prototype.eat = function () { console.log("nom nom nom"); };

Bird.prototype = Object.create(Animal.prototype);

var beagle = new Dog();

beagle.eat(); // prints "nom nom nom"
femmestem commented 8 years ago

Inheritance

Challenge 2: Inherit Behaviors From A Supertype

Updated: 08/22/16

Challenge Inherit Behaviors From A Supertype

Challenge Description

In the previous challenge, we created a supertype called Animal that defined behaviors shared by all animals:

function Animal() { };

Animal.prototype.eat = function()  {
console.log("nom nom nom");
}

In this and the next challenges, we will learn how to reuse Animal's methods inside Bird and Dog without defining them again by using a technique called inheritance.

This challenge will cover the first step: make an instance of the supertype (or parent).

We already know one way to create an instance of Animal using the new operator:

var animal = new Animal();

There are some disadvantages when using this syntax for inheritance, which are too complex for the scope of this challenge. Instead, we show a better approach:

var animal = Object.create(Animal.prototype);

Object.create(obj) creates a new object, and sets obj as the new object's prototype. Recall that the prototype is like the "recipe" for creating an object. By setting the prototype of animal to be Animal's prototype, we are effectively giving animal the same "recipe" as any other instance of Animal.

animal.eat(); // prints "nom nom nom"
animal instanceof Animal; //=> true

Instructions

Use Object.create to make two instances of Animal named duck and beagle

Challenge Seed


function Animal(){

}

Animal.prototype = {
    constructor: Animal, 
    eat: function() {
        console.log("nom nom nom");
    }
}

// Modify the code below this line

var duck =  
var beagle = 

duck.eat(); // Should print "nom nom nom"
beagle.eat(); //Should print "nom nom nom" 

Challenge Tests assert(typeof duck !== "undefined", 'message: Did you remember to define the variable duck?); assert(typeof beagle !== "undefined", 'message: Did you remember to define the variable beagle?);

assert(duck instanceof Animal, 'message: Did you remember to assign the Animal prototype to duck?') assert(beagle instanceof Animal, 'message: Did you remember to assign the Animal prototype to beagle?')

Challenge Solution

function Animal(){

}

Animal.prototype = {
    constructor: Animal, 
    eat: function() {
        console.log("nom nom nom");
    }
}

// Modify the code below this line

var duck =  Object.create(Animal.prototype); 
var beagle = Object.create(Animal.prototype); 

duck.eat(); // Should print "nom nom nom"
beagle.eat(); //Should print "nom nom nom" 
femmestem commented 8 years ago

Inheritance

Challenge 5: Add Own Methods To Inherited Prototype

Updated: 08/22/16

Challenge Add Own Methods To Inherited Prototype

Challenge Description A constructor function that inherits its prototype object from a super-type constructor function can still have its own methods in addition to inherited methods.

Let's use Bird for example, a constructor that inherits its prototype from Animal.

function Animal() {}
Animal.prototype.eat = function () { console.log("Nom nom nom"); };

function Bird() {}
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;

In addition to what is inherited from Animal, we want to add behavior that is unique to birds. Let’s give Bird a fly() function. we add a function to Bird's protoype the same way we do with any constructor function: Bird.prototype.fly = function () { console.log("I'm flying!"); };

Now instances of Bird will have both eat() and fly() methods.

var duck = new Bird;
duck.eat(); // prints "Nom nom nom"
duck.fly(); // prints "I'm flying!"

Instructions Add the necessary code to make beagle respond to eat() and bark().

Hint Objects inherit methods from other objects by cloning their prototype. The Object.create method will come in handy, and don't forget to reset the constructor property afterward!

Challenge Seed

function Animal(){};
Animal.prototype.eat = function () { console.log("Nom nom nom"); };

function Dog() {};

// Add code below this line

// Add code above this line

var beagle = new Dog;

beagle.eat(); // prints "Nom nom nom"
beagle.bark(); // prints "Woof!"

**Challenge Tests**
assert(typeof Animal.prototype.bark == "undefined", 'message: Only instances of Dog should respond to the .bark() method');

assert(!(typeof Dog.prototype.eat == "undefined"), 'message: Dog should inherit the .eat() method from Animal');

assert(beagle instanceof Animal, 'message: Dog should inherit the .eat() method from Animal');

assert(beagle.constructor === Dog, 'message: Did you remember to the constructor for Dog?');

**Challenge Solution**
```javascript
function Animal(){};
Animal.prototype.eat = function () { console.log("Nom nom nom"); };

function Dog() {};

// Add code below this line
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {};
// Add code above this line

var beagle = new Dog;

beagle.eat(); // prints "Nom nom nom"
beagle.bark();
femmestem commented 8 years ago

Inheritance

Challenge 6: Override Inherited Methods

Updated: 08/24/16

Challenge Override Inherited Methods

Challenge Description In previous lessons, we learned that an object can inherit its behavior (methods) from another object by cloning its prototype object, like this ChildObject.prototype = Object.create(ParentObject.prototype). We gave ChildObject its own methods by chaining them onto its prototype, like this ChildObject.prototype.methodName = function () {...}.

We can override an inherited method the same way by adding a method to ChildObject.prototype using the same method name as the one we want to override.

Here's an example of Bird overriding the eat() method inherited from Animal.

function Animal(){}

Animal.prototype.eat = function() { return "Nom nom nom"; };

function Bird(){}

// inherit methods first, followed by method overrides
Bird.prototype = Object.create(Animal.prototype);

// Bird.eat() overrides Animal.eat()
Bird.prototype.eat = function () { return "Peck peck peck"; };

If we have an instance var duck = new Bird and we call duck.eat(), here’s how JavaScript looks for the method on duck’s prototype chain:

  1. duck => Is eat() defined here? No.
  2. Bird => Is eat() defined here? => Yes. Execute it and stop searching.
  3. Animal => eat() is also defined here, but JavaScript stopped searching before reaching this level.
  4. Object => JavaScript stopped searching before reaching this level.

Instructions

Override the fly() method for Penguin so that it prints in the console "Alas, this is a flightless bird."

Challenge Seed

function Bird(){}

Bird.prototype.fly = function () { return "I'm flying!"; };

function Penguin(){}
Penguin.prototype = Object.create(Bird.prototype);
Penguin.prototype.constructor = Penguin;

// Only add code below this line

// Only add code above this line

var penguin = new Penguin;
console.log(penguin.fly());

Challenge Tests assert(penguin.fly() === "Alas, this is a flightless bird.", 'message: penguin.fly() should return "Alas, this is a flightless bird."');

assert((new Bird).fly() === "I'm flying!", 'message: bird.fly() should return "I'm flying!"');

assert(penguin.constructor === Penguin, 'message: Did you remember to the constructor for Penguin?');

Challenge Solution

function Bird(){}

Bird.prototype.fly = function () { return "I'm flying!"; };

function Penguin(){}
Penguin.prototype = Object.create(Bird.prototype);
Penguin.prototype.constructor = Penguin;

// Only add code below this line
Penguin.prototype.fly = function () {
    return "Alas, this is a flightless bird.";
}
// Only add code above this line

var penguin = new Penguin;
console.log(penguin.fly());
femmestem commented 8 years ago

Inheritance

Challenge 4: Reset An Inherited Constructor Property

Updated 08/24/16

Challenge Reset An Inherited Constructor Property

Challenge Description When an object inherits its prototype from another object, it also inherits the super-type’s constructor property.

Example:

function Bird(){};
Bird.prototype = Object.create(Animal.prototype);
var duck = new Bird;
duck.constructor // function Animal(){...}

Uh oh! We want duck and all instances of Bird to show that they were constructed by Bird. We have to manually set Bird's constructor property to the Bird object, like this: Bird.prototype.constructor = Bird. Now, duck.constructor returns function Bird(){...}.

Instructions

Fix the code so duck.constructor and beagle.constructor return their respective constructors.

Challenge Seed

function Animal(){}
function Bird(){}
function Dog(){}

Bird.prototype = Object.create(Bird.prototype);
Dog.prototype = Object.create(Bird.prototype);

//
// Add code here
//

var duck = new Bird;
var beagle = new Dog;

Challenge Tests assert(Animal.prototype.isPrototypeOf(Bird.prototype), 'message: Bird.prototype should be an instance of the Animal');

assert(duck.constructor === Bird, 'message: duck.constructor should return Bird');

assert(Animal.prototype.isPrototypeOf(Dog.prototype), 'message: Dog.prototype should be an instance of the Animal');

assert(beagle.constructor === Bird, 'message: beagle.constructor should return Dog');

Challenge Solution

function Animal(){}
function Bird(){}
function Dog(){}

Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);

Bird.prototype.constructor = Bird;
Dog.prototype.constructor = Dog;

var duck = new Bird;
var beagle = new Dog;
utsab commented 8 years ago

Challenge

Understand "own" properties

Challenge Description

In the following example, the Bird constructor defines two properties: name and numLegs

function Bird(name) {
    this.name  = name; 
    this.numLegs = 2; 
}

var duck = new Bird(“Donald”); 
var canary = new Bird(“Tweety”); 

name and numLegs are called own properties, because they are defined directly on the instance object. That means that duck and canary each has its own separate copy of these properties.

birds2 In fact every instance of Bird will have its own copy of these properties

The following code adds all of the own properties of duck to the array ownProps:

ownProps = []

for (var property in duck) {
    if(duck.hasOwnProperty(property)) {
        ownProps.push(property); 
    }
}

console.log(ownProps);  // prints [ ‘name’, 'numLegs' ]

Instructions

Add the own properties of canary to the array ownProps

Challenge Seed

function Bird(name) {
    this.name  = name; 
    this.numLegs = 2; 
}

var canary = new Bird(“Tweety”); 

ownProps = []

//Add your code below this line 

Challenge Solution

for (var property in canary) {
    if (canary.hasOwnProperty(property)) {
       ownProps.push(property);
    }
}

\ Challenge Tests **

assert(ownProps.includes('name') && ownProps.includes('numLegs'), "message: <code>ownProps</code> should include the values <code>'numLegs'</code> and <code>'name'</code>'");
utsab commented 8 years ago

Challenge

Use prototype properties to reduce duplicate code

Challenge Description

One downside of an own property is that it can lead to duplicate code. In the previous example, we saw that duck and canary each have their own separate copy of name and numLegs.

birds2

Since numLegs will probably have the same values for all instances of Bird, we essentially have a duplicated variable numLegs inside each Bird instance.

This may not be a big deal when we only have two instances, but imagine if we had millions of instances, that would be a LOT of duplicated variables.

A better way is to use Bird’s prototype. The prototype is an object that is shared among ALL instances of Bird. We’ll add numLegs to Bird’s prototype:

Bird.prototype.numLegs = 2

prototype3

Now all instances of Bird have the numLegs property.

console.log(duck.numLegs);  // prints 2
console.log(canary.numLegs);  // prints 2

Since all instances are automatically endowed with the properties on the prototype, you can think of a prototype as a "recipe" for creating objects.

Note that the prototype for duck and canary lives on the Bird constructor as Bird.prototype. Nearly every object in javascript has a prototype property which lives on the constructor function that created it.

Instructions

Add a numLegs property to the prototype of Dog

Challenge Seed

    function Dog(name) {
        this.name = name; 
    }

    var beagle = new Dog(“Snoopy”); 

    //Add your code below this line 

Challenge Solution

Dog.prototype.numLegs = 4; 

\ Challenge Tests **

assert(beagle.numLegs !== undefined, "message: <code>beagle</code> should have the property <code>'numLegs'</code>"); 
    assert(typeof(beagle.numLegs) === "number" , "message: <code>beagle.numLegs</code> should be a number"); 
    assert(beagle.hasOwnProperty('numLegs') === false, "message: <code>numLegs</code> should be a prototype property not an own property"); 
user512 commented 8 years ago

Challenge Iterate over all properties

Challenge Description

We have now seen two kinds of properties: own properties and prototype properties. own properties are defined directly on the object instance itself. prototype properties are defined on the prototype.

function Bird(name) {
    this.name = name;  //own property
}

Bird.prototype.numLegs = 2 //prototype property

var duck = new Bird(“Donald”); 

Here is how we add duck’s own properties to the array ownProps and prototype properties to the array prototypeProps:

var ownProps = []; 
var prototypeProps = [];

for (var property in duck) {
    if(duck.hasOwnProperty(property)) {
        ownProps.push(property); 
    } else {
        prototypeProps.push(property); 
    }
}

console.log(ownProps) // prints [‘name’ ]
console.log(prototypeProps) // prints [ 'numLegs’ ]

Instructions

Add all of the own properties of beagle to the array ownProps. Add all of the prototype properties of to the array prototypeProps.

Challenge Seed

function Dog(name) {
    this.name = name; 
}

Dog.prototype.numLegs = 4

var beagle = new Dog(“Snoopy”);

var ownProps = []; 
var prototypeProps = [];

//Add your code below this line 

Challenge Solution

for (var property in beagle) {
    if(beagle.hasOwnProperty(property)) {
        ownProps.push(property); 
    } else {
        prototypeProps.push(property); 
    }
}

console.log(ownProps); // prints "Snoopy"
console.log(prototypeProps); // prints 4

Challenge Tests

assert(ownProps.includes('name'), "message: <code>ownProps</code> should include <code>'name'</code>"); 
assert(prototypeProps.includes('numLegs'), "message: <code>prototypeProps</code> should include <code>'numLegs'</code>"); 
user512 commented 8 years ago

Challenge Use the "constructor" property

Challenge Description

There is a special “constructor” property located on the object instances duck and beagle we created in the previous challenges:


var duck = new Bird(); 
var beagle = new Dog(); 

console.log(duck.constructor);  //prints "Bird"
console.log(beagle.constructor);  //prints "Dog"

Note that the constructor property is equal to the constructor function that created the instance.

The advantage of the constructor property is that your code can inspect this property to find out what kind of object it is. One example illustrating how this could be used:

function joinBirdFraternity(candidate) {
    if (candidate.constructor === Bird) {
        return true; 
    } else {
        return false;  
    }
}

Note: Since the constructor property can be overwritten (as we’ll see in the next two sections) it’s generally better to use the instanceof method to check the type of an object.

Instructions

Write a joinDogFraternity function that takes a candidate parameter and returns true if the candidate is a Dog and returns false otherwise.

Challenge Seed


function Dog(name) {
    this.name = name; 
}

// Type your code below this line 
function joinDogFraternity(candidate) {

}

Challenge Solution


function joinDogFraternity(candidate) {
    if (candidate.constructor === Dog) {
        return true; 
    } else {
        return false; 
    }
}

Challenge Tests


assert(typeof(joinDogFraternity) === "function", "message: <code>joinDogFraternity</code> should be defined as a function"); 
assert(joinDogFraternity(new Dog("")) === true, "message: <code>joinDogFraternity</code> should return true if<code>candidate</code> is an instance of <code>Dog</code>"); 
user512 commented 8 years ago

Challenge

Change the prototype to a new object

Challenge Description

Up until now we have been adding properties to the prototype individually:

Bird.prototype.numLegs = 2 

This becomes tedious after more than a few properties.

Bird.prototype.eat = function() {
    console.log(“nom nom nom”); 
}

Bird.prototype.describe = function() {
    console.log(“My name is ” + this.name); 
}

A better way is to set the prototype to a new object that already contains the properties. In this way, the properties can be added all at once:


Bird.prototype = {
    numLegs: 2, 
    eat: function() {
        console.log(“nom nom nom”); 
    }, 
    describe = function() {
        console.log(“My name is ” + this.name); 
    }
}; 

Instructions

Add three properties numLegs, eat and describe to the prototype of Dog by setting the prototype to a new object.

Challenge Seed


function Dog(name) {
    this.name = name; 
}

Dog.prototype = {
    /* Your code goes here */
}

Challenge Solution


function Dog(name) {
    this.name = name; 
}

Dog.prototype = {
    numLegs: 4, 
    eat: function() {
        console.log("chomp"); 
    }, 
    describe: function() {
        console.log("My name is " + this.name); 
    }
}

Challenge Tests


assert((/Dog\.prototype[ ]*=[ ]*{/).test(code), "message: Dog.prototype should be set to a new object.");   
assert(Dog.prototype.numLegs !== undefined, "message: <code>Dog.prototype</code> should have the property <code>'numLegs'</code>"); 
assert(Dog.prototype.eat !== undefined, "message: <code>Dog.prototype</code> should have the property <code>'eat'</code>"); 
assert(Dog.prototype.describe !== undefined, "message: <code>Dog.prototype</code> should have the property <code>'describe'</code>"); 
user512 commented 8 years ago

Challenge Remember to set the "constructor" property when changing the prototype

Challenge Description

There is one crucial side effect of manually setting the prototype to a new object. We erased the constructor property! Our code in the previous challenge would print the following for duck

console.log(duck.constructor) // prints ‘undefined’.  Oops!  

To fix this, whenever we manually set a prototype to a new object, we must remember to define the constructor property.

Bird.prototype = {
    constructor: Bird, // define the constructor property
    numLegs: 2, 
    eat: function() {
        console.log(“nom nom nom”); 
    }, 
    describe = function() {
        console.log(“My name is ” + this.name); 
    }
}; 

Instructions

Define the "constructor" property on the Dog prototype.

Challenge Seed


function Dog(name) {
    this.name = name; 
}

//modify this section
Dog.prototype = {
    numLegs: 2, 
    eat: function() {
        console.log(“nom nom nom”); 
    }, 
    describe = function() {
        console.log(“My name is ” + this.name); 
    }
}; 

Challenge Solution

Dog.prototype = {
    constructor: Dog,
    numLegs: 4,
    eat: function() {
        console.log(“peck peck peck”); 
    }, 
    describe: function() {
        console.log(“My name is ” + this.name); 
    }
}; 

Challenge Tests

assert(Dog.prototype.constructor === Dog, "message: <code>Dog.prototype</code> should have the property <code>'constructor'</code>"); 
alookatommorow commented 8 years ago

Challenge

Define a Constructor Function

Challenge Description

Constructors are functions that create new objects. They define properties and behaviors that will belong to the new object. You can think of them as a blueprint for the creation of new objects.

Here is an example of a constructor:

function Bird () {
  this.name = 'Albert';
  this.color = 'blue';
  this.numLegs = 2;
}

This constructor defines a Bird object with properties name, color, and numLegs set to Albert, blue and 2, respectively.

Constructors follow a few conventions:

Constructors are defined with a capitalized name to distinguish them from other functions that are not constructors.

Constructors use the keyword this to set properties of the object they will create. Inside the constructor, this refers to the new object it will create.

Constructors define properties and behaviors instead of returning a value as other functions might.

Instructions:

Now create your own constructor, Dog, with properties name, color, and numLegs set to a string, a string, and a number, respectively.

Challenge Seed

// Your code here

Challenge Solution

function Dog () {
  this.name = 'somestring';
  this.color = 'somecolor';
  this.numLegs = 4;
}

Tests

assert(typeof (new Dog()).name === 'string', 'message: <code>Dog</code> should have a <code>name</code> attribute set to a string');
assert(typeof (new Dog()).color === 'string', 'message: <code>Dog</code> should have a <code>color</code> attribute set to a string');
assert(typeof (new Dog()).numLegs === 'number', 'message: <code>Dog</code> should have a <code>numLegs</code> attribute set to a number');
alookatommorow commented 8 years ago

Challenge

Use a Constructor to Create Objects

Challenge Description

Let’s see our Bird constructor from the previous challenge in action:

function Bird () {
  this.name = 'Albert';
  this.color  = 'blue';
  this.numLegs = 2;
  // ‘this’ inside the constructor always refers to the object being created
}

var blueBird = new Bird();

Notice that we use the new operator when calling our constructor. This tells JavaScript that we want to create a new instance of Bird. Without the new operator, this inside the constructor would not point to the newly created object, giving us unexpected results.

Now blueBird has all the properties defined inside the Bird constructor:

blueBird.name; // => Albert
blueBird.color; // => blue
blueBird.numLegs; // => 2

Just like any other object, its properties can be accessed and modified:

blueBird.name = 'Elvira';
blueBird.name; // => Elvira

Instructions:

Use the Dog constructor from the last lesson to create a new instance of Dog, assigning it to a variable hound.

Challenge Seed

function Dog () {
  this.name = 'Rupert';
  this.color = 'brown';
  this.numLegs = 4;
}

//your code here  

Challenge Solution

var hound = new Dog();

Tests

assert(hound instanceof Dog, 'message: <code>hound</code> should be created using the <code>Dog</code> constructor');
alookatommorow commented 8 years ago

Challenge

Extend Constructors to Receive Arguments

Challenge Description

The Bird and Dog constructors we created were pretty cool. However, notice that all Birds we create with our Bird constructor are automatically named Albert, are blue in color, and have two legs. What if we want birds with different values for name and color? We could change the properties of each bird manually but that would be a lot of work:

  var swan = new Bird();
  swan.name = 'Carlos';
  swan.color = 'white';

Suppose we were writing a program to keep track of hundreds or even thousands of different birds in an aviary. It would be time consuming to create all the birds and go through each of them, setting their properties to different values.

To more easily enable the construction of different Bird objects, we can design our Bird constructor to accept parameters:

 function Bird(name, color) {
    this.name = name;
    this.color = color;
    this.numLegs = 2;
  }

We can then pass in the values that will define our unique bird as arguments to our Bird constructor:

var cardinal = new Bird('Bruce', 'red');

This gives a new instance of Bird with name and color properties set to Bruce and red, respectively. The numLegs property is still set to 2.

As we can see, cardinal has these properties:

  cardinal.name // => Bruce
  cardinal.color // => red
  cardinal.numLegs // => 2

The flexibility of our constructor has increased. We can now define the properties we want to assign to each Bird at the time we create it.

This capability brings us closer to understanding why JavaScript constructors are so useful. Constructors allow us to group objects together based on shared characteristics and behavior and define a blueprint that automates their creation.

Instructions:

Create another Dog constructor. This time, set it up to take the arguments name and color, and have the property numLegs fixed at 4. Then create a new Dog, passing it two strings for the name and color properties, setting it equal to the variable terrier.

Challenge Seed

function Dog() {
   // your code here
}
// your code here

Challenge Solution

function Dog(name, color) {
  this.name = name;
  this.color = color;
  this.numLegs = 4;
}

var terrier = new Dog('Clifford', 'red');

Tests

assert((new Dog('Clifford')).name === 'Clifford', 'message: <code>Dog</code> should receive arguments <code>name</code> and <code>color</code> and set them to their respective properties');
assert((new Dog('Clifford', 'yellow')).color === 'yellow', 'message: <code>Dog</code> should receive arguments <code>name</code> and <code>color</code> and set them to their respective properties');
assert((new Dog('Clifford')).numLegs === 4, 'message: <code>Dog</code> should have property <code>numLegs</code> set to 4');
assert(terrier instanceof Dog, 'message: <code>terrier</code> should be created using the <code>Dog</code> constructor');
alookatommorow commented 8 years ago

Challenge

Verify an Object's Constructor with instanceof

Challenge Description

Anytime we create a new object using a constructor function, that object is said to be an instance of its constructor. JavaScript gives us a convenient way to verify this programmatically. Enter the instanceof operator. instanceof allows us to compare an object to a constructor, returning true or false based on whether or not that object was created with the constructor.

var Bird = function(name, color) {
  this.name = name;
  this.color = color;
  this.numLegs = 2;
}

var crow = new Bird('Alexis', 'black');

crow instanceof Bird; // => true

If we create an object without using a constructor, instanceof will verify that it is not an instance of that constructor:

var canary = {
  name: 'Mildred',
  color: 'Yellow',
  numLegs: 2
}

canary instanceof Bird; // => false

Instructions:

Create a new instance of the House constructor, calling it myHouse and passing a number of bedrooms. Then, use instanceof to verify that it is an instance of House.

Challenge Seed

var House = function(numBedrooms) {
  this.numBedrooms = numBedrooms;
}

//your code here
var myHouse = ;
 instanceof ;

Challenge Solution

var myHouse = new House(3000);
myHouse instanceof House;

Tests

assert(typeof myHouse.numBedrooms === number, 'message: <code>myHouse</code> should have a <code>numBedrooms</code> attribute set to a number');
assert(editor.getValue().match(/(myHouse instanceof House)/), 'message: Be sure to verify that <code>myHouse</code> is an instance of <code>House</code> using the <code>instanceof</code> operator');
user512 commented 8 years ago

Challenge

Understand where an object’s prototype comes from

Challenge Description

Just like you inherited genes from your parents, an object inherits its prototype directly from the constructor function that created it. For example, here we use the Bird constructor to create the duck object.

function Bird(name) {
    this.name = name;
}

var duck = new Bird(“Donald”);

duck inherits its prototype from Bird. We can show this relationship with the isPrototypeOf method:

Bird.prototype.isPrototypeOf(duck);  // => true

Instructions

Fix the code so that it shows the correct prototype of beagle

Challenge Seed

function Dog(name) {
    this.name = name;
}

var beagle = new Dog(“Snoopy”);

// Fix the code below so that it evaluates to “true”
???.isPrototypeOf(beagle);

Challenge Solution

function Dog(name) {
    this.name = name;
}

var beagle = new Dog(“Snoopy”);

// Fix the code below so that it evaluates to “true”
Dog.prototype.isPrototypeOf(beagle);

Challenge Tests


assert(/Dog\.prototype\.isPrototypeOf/.test(code), "message: Show that <code>Dog.prototype</code> is the prototype of <code>beagle</code>");
user512 commented 8 years ago

Challenge

Understand the prototype chain

Challenge Description

All objects in javascript (with a few exceptions) have a prototype. It turns out that an object’s prototype itself is an object.

function Bird(name) {
    this.name = name;
}

typeof Bird.prototype; // => object

Because a prototype is an object, a prototype can have its own prototype! In this case, the prototype of Bird.prototype is Object.prototype:

Object.prototype.isPrototypeOf(Bird.prototype);  // => true

How is this useful to us? You may recall the hasOwnProperty method from a previous challenge:


var duck = new Bird(“donald”);
duck.hasOwnProperty(“name”); // => true

The hasOwnProperty method is defined in Object.prototype, which can be accessed by Bird.prototype, which can then be accessed by duck. This illustrates the prototype chain.

In this prototype chain, we say that Bird is the supertype for duck, while duck is the subtype. Object is a supertype for both Bird and duck.

Object is in fact a supertype for all objects in javascript. Therefore any object will respond to the hasOwnProperty method.

Instructions

Modify the code to show the correct prototype chain

Challenge Seed

function Dog(name) {
    this.name = name;
}

var beagle = new Dog(“Snoopy”);

Dog.prototype.isPrototypeOf(beagle);  // => true

// Fix the code below so that it evaluates to “true”
???.isPrototypeOf(Dog.prototype);

Challenge Solution

function Dog(name) {
    this.name = name;
}

var beagle = new Dog(“Snoopy”);

Dog.prototype.isPrototypeOf(beagle);  // => true

// Fix the code below so that it evaluates to “true”
Object.prototype.isPrototypeOf(Dog.prototype);

Challenge Tests


assert(/Object\.prototype\.isPrototypeOf/.test(code), "message: Show that <code>Dog.prototype</code> is the prototype of <code>beagle</code>");
QuincyLarson commented 8 years ago

@user512 Excellent work, Tom! These are coming along great. You do an excellent job of explaining these concepts, and these challenges are really well conceived.

user512 commented 8 years ago

Credit to @utsab. He is great at leading the team and teaching these concepts.

utsab commented 8 years ago

Here is the final list of topics. Note that this is different than what is posted in the first comment. @alayek, can you please update the first comment with this new list? Thank you.

Objects

Constructors

Prototypes

Inheritance

Other

The final version of all of these challenges is located in this google doc

alayek commented 8 years ago

@utsab yeah I was just about to update the first comment. Thanks!

QuincyLarson commented 8 years ago

@utsab Excellent! Could you check the boxes that correspond to your created challenges so we can see which challenges remain to be created?

femmestem commented 8 years ago

Inheritance

Challenge 1: Don't Repeat Yourself

Challenge Don't Repeat Yourself

Challenge Description There's a principle in programming called "Don't Repeat Yourself (DRY)". The reason repeated code is a problem is because any change requires fixing code in multiple places, which means more work for programmers and more room for errors.

Notice in the example below that the describe method is shared by Bird and Dog:

Bird.prototype = {
    constructor: Bird, 
    describe: function() {
        console.log("My name is " + this.name);
    }
};

Dog.prototype = {
    constructor: Dog,
    describe: function() {
        console.log("My name is " + this.name);
    }
};

The describe method is therefore repeated in two places. We can make our code more DRY by creating a supertype (or parent) called Animal:

function Animal(){
};

Animal.prototype = {
    constructor: Animal, 
    describe: function() {
        console.log("My name is " + this.name);
    }
};

Since Animal includes the describe method, we can then remove it from Bird and Dog.

Bird.prototype = {
    constructor: Bird
};

Dog.prototype = {
    constructor: Dog
};

Instructions

The eat method is repeated in both Cat and Bear. Make the code more DRY by moving the eat method to the Animal supertype.

Challenge Seed

function Cat(name) {
    this.name = name; 
};

Cat.prototype = {
    constructor: Cat, 
    eat: function() {
        console.log("nom nom nom");
    }
};

function Bear(name) {
    this.name = name; 
};

Bear.prototype = {
    constructor: Bear, 
    eat: function() {
        console.log("nom nom nom");
    }
};

function Animal(){
};

Animal.prototype = {
    constructor: Animal
};

Challenge Tests

Test that Animal.prototype has the eat method. Test that Bear.prototype does not have the eat method Test that Cat.prototype does not have the eat method

Challenge Solution

function Cat(name) {
    this.name = name; 
};

Cat.prototype = {
    constructor: Cat
};

function Bear(name) {
    this.name = name; 
};

Bear.prototype = {
    constructor: Bear;
};

function Animal(){

};

Animal.prototype = {
    constructor: Animal, 
    eat: function() {
        console.log("nom nom nom");
    }
};
utsab commented 8 years ago

@QuincyLarson, I updated the list of topics and checked off the completed challenges. Every challenge except one (calling a supertype method) was created.

Since there were a few people creating challenges for this topic, I went through everyone's challenges and updated them for stylistic consistency. The final version of all of these challenges is located in this google doc.

Is this an acceptable way to submit the final versions of the challenges?

QuincyLarson commented 8 years ago

@utsab yes - this should work fine. Rather than asking you to manually port these over to GitHub, any time you have available would be better invested in helping design the remaining challenges: https://github.com/FreeCodeCamp/CurriculumExpansion/issues/46

Thanks again!