Skip to content
This repository was archived by the owner on Aug 31, 2019. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions notes/inheritance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really really fun! I'd like to rephrase something though. Objects in Javascript don't necessarily "Inherit" they way that you may be used to from other OO Languages. It's more that a "Parent" class would be "Delegating" do it's "Sub-classes". I'm sure you're aware of these intricacies, but I wanted to make it very clear Here is a link to a great article that talks about Prototypal 'inheritance' which really should say prototypal 'delegation'

Let's say we have a class Monster. This class will define all of our Monsters at a generic level.
It will hold attributes that each Monster, be it a Zombie, a Skeleton, a Banshee, etc should have.
**/
class Monster {
constructor(name, hitpoints, level, inventory, nickname) {
this.name = name;
this.hitpoints = hitpoints;
this.level = level;
this.inventory = inventory || [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could potentially just default this in the constructor parens. constructor(inventory = [])
which would allow you to forego the ||.

this.nickname = nickname;
}
getDisplayName() {
return this.nickname || this.name; //if no nickname was provided, nickname will be undefined so name will be returned.
}
onAttack() {
console.log(`${this.getDisplayName()} attacked for 1 damage.`);
}
onDamage() {
console.log(`${this.getDisplayName()} took ${this.hitpoints - --this.hitpoints} damage!`);
if (this.hitpoints <= 0) {
this.onDeath();
}
}
onDeath() {
console.log(`${this.getDisplayName()} died!`);
if(this.inventory.length > 0) {
console.log(`${this.getDisplayName()} dropped: `);
this.inventory.forEach((item) => console.log(`\t${item}`));
} else {
console.log(`${this.getDisplayName()} didn't drop anything :(`);
}
}
}

/**
We now have the basic features a monster should have as well as default onAttack and onDamage methods that will apply to any
Monsters that don't come with their own. Lets create our different Monsters and extend the Monster class so they all get these features.
**/
class Zombie extends Monster {
constructor(stats) {
// You call `super` which calls Monster's constructor and lets Zombie inherit everything from Monster
super("Zombie", stats.hitpoints, stats.level, stats.inventory || ['sword'], stats.nickname);
this.rotten = 'hella';
}
}

class Skeleton extends Monster {
constructor(hitpoints, level, inventory = ["bow"], nickname) {
// You call `super` which calls Monster's constructor and lets Skeleton inherit everything from Monster
super("Skeleton", hitpoints, level, inventory, nickname);
}
}

class Banshee extends Monster {
constructor(hitpoints, level, inventory = undefined, nickname) {
// You call `super` which calls Monster's constructor and lets Banshee inherit everything from Monster
super("Banshee", hitpoints, level, inventory, nickname);
}
onAttack() {
this.scream();
// even though we are making our own onAttack method, we can still call the one from super
super.onAttack();
}
scream() {
console.log("AHHHHHH!!!!")
}
}

// Set up our dope battle simulator right here
function battle(mon1, mon2) {
if(Math.random() >= 0.5) {
mon1.onAttack();
mon2.onDamage();
} else {
mon2.onAttack();
mon1.onDamage();
}
}

// Now we make some Monsters
const zombie = new Zombie({hitpoints: 5, level: 3});
const skeleton = new Skeleton(5, 3);
const banshee = new Banshee(10, 3);
const fred = new Zombie({hitpoints: 1, level: 1, nickname: "Fred"});
const jill = new Banshee(2000, 1000, inventory = ['The God Staff of Omar Illingisisisisisisi', 'The Magic School Bus Season 1 Collectors Edition'], "Hillary, Joe's Mom");

while (zombie.hitpoints > 0 && skeleton.hitpoints > 0) {
battle(skeleton, zombie);
console.log(" ");
}

while (fred.hitpoints > 0 && banshee.hitpoints > 0) {
battle(fred, banshee);
console.log(" ");
}

while (banshee.hitpoints > 0 && jill.hitpoints > 0) {
battle(banshee, jill);
console.log(" ");
}

console.log(" ");
console.log("He has risin! Oh glorious Fred, may he bring glory to the heavens and rain fire on all those who appose him!!!");
console.log(" ");
console.log(" ");

fred.hitpoints = 200000;
fred.level = 9000+1;
fred.inventory.push('The God Staff of Omar Illingisisisisisisi +2');

fred.scream = function() {
console.log("Ooooga Boooggggaaa!!");
}

fred.onAttack = function() {
this.scream();
console.log(`${this.getDisplayName()} attacked for !@#!$%@#~! damage.`);
jill.hitpoints = -100000;
}

while (fred.hitpoints > 0 && jill.hitpoints > 0) {
battle(fred, jill);
console.log(" ");
}

// Some further tests to show how these interact
console.log(`typeof zombie: ${typeof zombie}`);
console.log(`zombie instanceof Zombie: ${zombie instanceof Zombie}`);
console.log(`zombie instanceof Monster: ${zombie instanceof Monster}`);
console.log(`zombie instanceof Skeleton: ${zombie instanceof Skeleton}`);
console.log(`zombie instanceof Banshee: ${zombie instanceof Banshee}`);
console.log(`typeof zombie === typeof skeleton: ${typeof zombie === typeof skeleton}`);
console.log(`typeof zombie === typeof fred: ${typeof zombie === typeof fred}`);
// console.log(`zombie instanceof fred: ${zombie instanceof fred}`); //error because fred isn't a class/constructor.
57 changes: 57 additions & 0 deletions notes/this-scope.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
class Fruit{
constructor(type, color){
this.getType = function(){return type};
this.getColor = () => color;
}
}

const apple = new Fruit("Apple", "Red");

// Fruit.prototype.message = () => `I am a ${this.getColor()} ${this.getType()}`;
// console.log(apple.message());
/**
Uncaught TypeError: this.getColor is not a function
at Fruit.message (<anonymous>:10:48)
at <anonymous>:12:19
**/

Fruit.prototype.message = function() {
return `I am a ${this.getColor()} ${this.getType()}`;
};

console.log(apple.message());
/**
I am a Red Apple
**/

const orange = new Fruit("Orange", "Orange");

let fruitMessage = apple.message;

console.log(fruitMessage);
// [Function]

console.log(fruitMessage.call(orange));
// I am a Orange Orange
console.log(fruitMessage.apply(orange));
// I am a Orange Orange

// console.log(fruitMessage());
/** TypeError: this.getColor is not a function
`this` is evaluated when the code is run rather than when
the object is created. By calling fruitMessage() in this way,
you have taken apple.message out of apple's scope and moved it
into the global scope. `this.getColor()` is now looking for `getColor()`
in the global scope which is undefined.
**/

fruitMessage = apple.message.bind(orange);
/** bind doesn't execute the function
it hold onto it and will apply the `this` scope when you call it later
**/

console.log(fruitMessage);
// [Function]

console.log(fruitMessage());
// I am a Orange Orange!
34 changes: 34 additions & 0 deletions src/arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,67 @@ const each = (elements, cb) => {
// Iterates over a list of elements, yielding each in turn to the `cb` function.
// This only needs to work with arrays.
// based off http://underscorejs.org/#each
for (let i = 0; i < elements.length; i++) {
cb(elements[i], i);
}
};

const map = (elements, cb) => {
// Produces a new array of values by mapping each value in list through a transformation function (iteratee).
// Return the new array.
const arr = [];
each(elements, (item, index) => { arr.push(cb(item, index)); });
return arr;
};

const reduce = (elements, cb, memo = elements.shift()) => {
// Combine all elements into a single value going from left to right.
// Elements will be passed one by one into `cb`.
// `memo` is the starting value. If `memo` is undefined then make `elements[0]` the initial value.
if (typeof memo === 'undefined') {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be unnecessary as you have defaulted already in the function parens

memo = elements[0];
}
each(elements, (item, index) => { memo = cb(memo, item, index); });
return memo;
};

const find = (elements, cb) => {
// Look through each value in `elements` and pass each element to `cb`.
// If `cb` returns `true` then return that element.
// Return `undefined` if no elements pass the truth test.
for (let i = 0; i < elements.length; i++) {
if (cb(elements[i])) {
return elements[i];
}
}
return undefined;
};

const filter = (elements, cb) => {
// Similar to `find` but you will return an array of all elements that passed the truth test
// Return an empty array if no elements pass the truth test
const array = [];
for (let i = 0; i < elements.length; i++) {
if (cb(elements[i])) {
array.push(elements[i]);
}
}
return array;
};

const flatten = (elements) => {
// Flattens a nested array (the nesting can be to any depth).
// Example: flatten([1, [2], [3, [[4]]]]); => [1, 2, 3, 4];
const array = [];
const cb = (item) => {
if (item instanceof Array) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, instance of is great, you should look into Array.isArray()

each(item, cb);
} else {
array.push(item);
}
};
each(elements, cb);
return array;
};

/* eslint-enable no-unused-vars, max-len */
Expand Down
27 changes: 27 additions & 0 deletions src/class.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@
// Add a method called `comparePasswords`. `comparePasswords` should have a parameter
// for a potential password that will be compared to the `password` property.
// Return true if the potential password matches the `password` property. Otherwise return false.
const arrayMethods = require('../src/arrays');

class User {
constructor(options) {
this.email = options.email;
this.password = options.password;
}
comparePasswords(compare) {
return this.password === compare;
}
}

/* eslint-disable no-undef */ // Remove this comment once you write your classes.

Expand All @@ -18,7 +28,24 @@
// Cat should have the property `name` that is set in the constructor and the method
// `meow` that should return the string `<name> meowed!` where `<name>` is the `name`
// property set on the Cat instance.
class Animal {
constructor(options) {
this.age = options.age;
}
growOlder() {
return ++this.age;
}
}

class Cat extends Animal {
constructor(options) {
super(options);
this.name = options.name;
}
meow() {
return `${this.name} meowed!`;
}
}

module.exports = {
User,
Expand Down
18 changes: 18 additions & 0 deletions src/closure.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
// Complete the following functions.
const arrayMethods = require('../src/arrays');

const counter = () => {
// Return a function that when invoked increments and returns a counter variable.
// Example: const newCounter = counter();
// newCounter(); // 1
// newCounter(); // 2
let c = 0;
return () => ++c;
};

const counterFactory = () => {
// Return an object that has two methods called `increment` and `decrement`.
// `increment` should increment a counter variable in closure scope and return it.
// `decrement` should decrement the counter variable and return it.
let c = 0;
return { increment: () => ++c, decrement: () => --c };
};

const limitFunctionCallCount = (cb, n) => {
// Should return a function that invokes `cb`.
// The returned function should only allow `cb` to be invoked `n` times.
return (...rest) => {
if (n-- > 0) {
return cb(...rest);
}
return null;
};
};

const cacheFunction = (cb) => {
Expand All @@ -25,6 +36,13 @@ const cacheFunction = (cb) => {
// If the returned function is invoked with arguments that it has already seen
// then it should return the cached result and not invoke `cb` again.
// `cb` should only ever be invoked once for a given set of arguments.
const cache = {};
return (arg) => {
if (!(arg in cache)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well done!

cache[arg] = cb(arg);
}
return cache[arg];
};
};

/* eslint-enable no-unused-vars */
Expand Down
Loading