From 2568e94f8331d048014d84101d985aa119ad5bb6 Mon Sep 17 00:00:00 2001 From: Alexander Aleksanyan Date: Wed, 6 Dec 2017 10:21:29 -0800 Subject: [PATCH] add and pass all tests --- package-lock.json | 18 ++++++------- src/arrays.js | 53 ++++++++++++++++++++++++++++++++++++++ src/class.js | 50 ++++++++++++++++++++++++++++++++---- src/closure.js | 65 +++++++++++++++++++++++++++++++++++++++++++++-- src/es6.js | 39 +++++++++++++--------------- src/objects.js | 20 +++++++++++++++ src/recursion.js | 44 +++++++++++++++++++++++++++++++- src/this.js | 16 +++++++++++- 8 files changed, 266 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2d7130..810aa7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3695,15 +3695,6 @@ } } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -3724,6 +3715,15 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/src/arrays.js b/src/arrays.js index b995952..006a76c 100644 --- a/src/arrays.js +++ b/src/arrays.js @@ -8,34 +8,87 @@ 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 + if (Array.isArray(elements)) { + for (let i = 0; i < elements.length; i++) { + cb(elements[i], i, elements); + } + } else if (elements === null) { + return elements; + } }; 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 result = []; + + each(elements, (item) => { + result.push(cb(item)); + }); + + return result; }; 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. + let memoUndefined = arguments.length < 3; + each(elements, (element, index) => { + if (memoUndefined) { + memoUndefined = false; + memo = element; + } else { + return memo = cb(memo, element, 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. + const arr = []; + + each(elements, (element, index) => { + if (cb(element, index)) { + arr.push(element); + } + }); + + if (arr.length === 0) { + return undefined; + } + + return arr[0]; }; 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 arr = []; + each(elements, (element, index) => { + if (cb(element, index)) { + arr.push(element); + } + }); + + return arr; }; /* Extra Credit */ const flatten = (elements) => { // Flattens a nested array (the nesting can be to any depth). // Example: flatten([1, [2], [3, [[4]]]]); => [1, 2, 3, 4]; + each(elements, (element) => { + if (Array.isArray(element)) { + elements = flatten([].concat([], ...elements)); + } + }); + + return elements; }; /* eslint-enable no-unused-vars, max-len */ diff --git a/src/class.js b/src/class.js index 8276e29..ebe3bc5 100644 --- a/src/class.js +++ b/src/class.js @@ -1,4 +1,5 @@ -// Create a class called User. +// Part 1 +// Create a class called User using the ES6 class keyword. // The constructor of the class should have a parameter called `options`. // `options` will be an object that will have the properties `email` and `password`. // Set the `email` and `password` properties on the class. @@ -6,21 +7,60 @@ // 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. +// code here -/* eslint-disable no-undef */ // Remove this comment once you write your classes. +class User { + constructor(options) { + this.email = options.email; + this.password = options.password; + } + comparePasswords(somePassword) { + return somePassword === this.password; + } +} -// Create a class called `Animal` and a class called `Cat`. +// Part 2 +// Create a class called `Animal` and a class called `Cat` using ES6 classes. // `Cat` should extend the `Animal` class. // Animal and Cat should both have a parameter called `options` in their constructors. // Animal should have the property `age` that's set in the constructor and the method -// `growOlder` that returns the age. +// `growOlder` that returns the age after incrementing it. // Cat should have the property `name` that is set in the constructor and the method // `meow` that should return the string ` meowed!` where `` is the `name` // property set on the Cat instance. +// code here + +/* eslint-disable no-undef */ + +class Animal { + constructor(options, age) { + this.options = options; + this.age = options.age; + } + + growOlder() { + this.age = this.age + 1; + return this.age; + } +} + +class Cat extends Animal { + constructor(options, name, age) { + super(options, name, age); + this.options = options; + this.name = options.name; + this.age = options.age; + } + + meow() { + return `${this.name} meowed!`; + } +} module.exports = { User, - Cat + Cat, + Animal, }; diff --git a/src/closure.js b/src/closure.js index 2d6592f..cadb176 100644 --- a/src/closure.js +++ b/src/closure.js @@ -5,20 +5,47 @@ const counter = () => { // Example: const newCounter = counter(); // newCounter(); // 1 // newCounter(); // 2 + let count = 0; + return () => { + ++count; + return count; + }; }; 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 s = 0; + return { + increment: () => { + s += 1; + return s; + }, + decrement: () => { + s -= 1; + return s; + }, + }; }; const limitFunctionCallCount = (cb, n) => { // Should return a function that invokes `cb`. // The returned function should only allow `cb` to be invoked `n` times. + let count = 0; + + return (...args) => { + if (n === count) { + return null; + } + + count++; + return cb(...args); + }; }; -/* Extra Credit */ +/* STRETCH PROBLEM */ + const cacheFunction = (cb) => { // Should return a funciton that invokes `cb`. // A cache (object) should be kept in closure scope. @@ -26,6 +53,40 @@ 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 storage = {}; + const args = []; + const tempCB = cb; + let tempFunc = tempCB.toString().split(' ')[1]; + if (tempCB !== undefined) { + const ourFunc = tempCB.toString().split(' ')[1].split(''); + + for (let i = 0; i <= ourFunc.indexOf('(') + 1; i++) { + ourFunc.splice(ourFunc[i], 1); + } + + tempFunc = ourFunc; + tempFunc.shift(); + tempFunc.pop(); + + console.log('OUR NEW FUNC SHOUDL BE: ', tempFunc); + } + + console.log(tempFunc[0]); + + if (storage[tempFunc[0]] === undefined) { + storage[tempFunc[0]] = cb(); + } + + console.log('RES IS: ', cb(tempFunc[0])); + + return function () { + const arg = tempFunc[0]; + if (!storage[arg]) { + storage[arg] = cb(arg); + } + + return storage[arg]; + }; }; /* eslint-enable no-unused-vars */ @@ -34,5 +95,5 @@ module.exports = { counter, counterFactory, cacheFunction, - limitFunctionCallCount + limitFunctionCallCount, }; diff --git a/src/es6.js b/src/es6.js index eb846ab..1edba8e 100644 --- a/src/es6.js +++ b/src/es6.js @@ -7,50 +7,47 @@ //---------------- // const, =>, default parameters, arrow functions default return statements using () -var food = 'pineapple'; +let food = `pineapple`; -var isMyFavoriteFood = function(food) { - food = food || 'thousand-year-old egg'; //This sets a default value if `food` is falsey - return food === 'thousand-year-old egg'; +const isMyFavoriteFood = (food) => { + food = food || `thousand-year-old egg`; //This sets a default value if `food` is falsey + return food === `thousand-year-old egg`; }; -var isThisMyFavorite = isMyFavoriteFood(food); +let isThisMyFavorite = isMyFavoriteFood(food); //---------------- //const, class, template literals, enhanced object literals (foo: foo, -> foo,) -var User = function(options) { +const User = (options) => { this.username = options.username; this.password = options.password; - this.sayHi = function() { - return this.username + ' says hello!'; + this.sayHi = () => { + return `${this.username} says hello!`; }; } -var username = 'JavaScriptForever'; -var password = 'password'; +let username = `JavaScriptForever`; +let password = `password`; -var me = new User({ - username: username, - password: password, -}); +let me = new User({ username, password }); // ---------------- // let, const, =>, ... (spread operator) -var addArgs = function () { - var sum = 0; - for (var i = 0; i < arguments.length; i++) { +const addArgs = () => { + let sum = 0; + for (let i = 0; i < arguments.length; i++) { sum += arguments[i]; } return sum; }; -var argsToCb = function (cb) { - var args = Array.prototype.slice.call(arguments); - return cb.apply(null, args.splice(1)); +const argsToCb = (cb) => { + const args = Array.prototype.slice.call(arguments); + return cb(...args.splice(1)); }; -var result = argsToCb(addArgs, 1, 2, 3, 4, 5); //result should be 15 +let result = argsToCb(addArgs, 1, 2, 3, 4, 5); //result should be 15 /* eslint-enable */ diff --git a/src/objects.js b/src/objects.js index ba39c6c..92a44e0 100644 --- a/src/objects.js +++ b/src/objects.js @@ -5,34 +5,54 @@ const keys = (obj) => { // Retrieve all the names of the object's properties. // Return the keys as strings in an array. // Based on http://underscorejs.org/#keys + return Object.keys(obj); }; const values = (obj) => { // Return all of the values of the object's own properties. // Ignore functions // http://underscorejs.org/#values + return Object.values(obj); }; const mapObject = (obj, cb) => { // Like map for arrays, but for objects. Transform the value of each property in turn. // http://underscorejs.org/#mapObject + Object.keys(obj).forEach(el => obj[el] = cb(obj[el])); + + return obj; }; const pairs = (obj) => { // Convert an object into a list of [key, value] pairs. // http://underscorejs.org/#pairs + return Object.keys(obj).map(el => [el, obj[el]]); }; const invert = (obj) => { // Returns a copy of the object where the keys have become the values and the values the keys. // Assume that all of the object's values will be unique and string serializable. // http://underscorejs.org/#invert + Object.keys(obj).forEach((el) => { + obj[obj[el]] = el; + delete obj[el]; + }); + + return obj; }; + const defaults = (obj, defaultProps) => { // Fill in undefined properties that match properties on the `defaultProps` parameter object. // Return `obj`. // http://underscorejs.org/#defaults + Object.keys(defaultProps).map(el => el).forEach((el, i) => { + if (!obj[el]) { + obj[el] = defaultProps[el]; + } + }); + + return obj; }; /* eslint-enable no-unused-vars */ diff --git a/src/recursion.js b/src/recursion.js index eb65c57..6395b4d 100644 --- a/src/recursion.js +++ b/src/recursion.js @@ -3,19 +3,61 @@ const nFibonacci = (n) => { // fibonacci sequence: 1 2 3 5 8 13 ... // return the nth number in the sequence + let a = 1; + let b = 0; + let temp; + + while (n >= 0) { + temp = a; + a += b; + b = temp; + n--; + } + + return b; }; const nFactorial = (n) => { // factorial example: !5 = 5 * 4 * 3 * 2 * 1 // return the factorial of `n` + const myArray = Array.from({ length: n + 1 }, (v, i) => i).reverse(); + myArray.pop(); + return myArray.reduce((acc, curr) => acc * curr, 1); +}; + + +const leavesHelper = (obj, sample, result) => { + Object.keys(obj).forEach((el) => { + if (obj[el] !== sample && Object.values(obj[el]).length < 1) { + result = false; + } else if (Object.values(obj[el]).length > 0) { + result = leavesHelper(obj[el], sample, result); + } + }); + + return result; }; /* Extra Credit */ -const checkMatchingLeaves = (obj) => { +const checkMatchingLeaves = (obj, result = false) => { // return true if every property on `obj` is the same // otherwise return false + const sample = Object.values(obj)[0]; + result = true; + const a = Object.keys(obj); + + a.forEach((el) => { + if (obj[el] !== sample && Object.values(obj[el]).length < 1) { + result = false; + } else if (Object.values(obj[el]).length > 0) { + result = leavesHelper(obj[el], sample, result); + } + }); + + return result; }; + /* eslint-enable no-unused-vars */ module.exports = { diff --git a/src/this.js b/src/this.js index 8ea3020..8fc6d8f 100644 --- a/src/this.js +++ b/src/this.js @@ -2,23 +2,37 @@ // There are no tests for this file. // To verify your code works you can run this file using `node this.js` while in the `/src` folder +/* part 1 */ + class User { constructor(options) { // set a username and password property on the user object that is created + this.username = options.username; + this.password = options.password; } // create a method on the User class called `checkPassword` // this method should take in a string and compare it to the object's password property // return `true` if they match, otherwise return `false` + checkPassword(somePassword) { + return this.password === somePassword; + } } -const me = new User({ username: 'LambdaSchool', password: 'correcthorsebatterystaple' }); +const me = new User({ + username: 'LambdaSchool', + password: 'correcthorsebatterystaple', +}); + const result = me.checkPassword('correcthorsebatterystaple'); // should return `true` +/* part 2 */ + const checkPassword = function comparePasswords(passwordToCompare) { // recreate the `checkPassword` method that you made on the `User` class // use `this` to access the object's `password` property. // do not modify this function's parameters // note that we use the `function` keyword and not `=>` + return Object.prototype.call(User.checkPassword).apply(passwordToCompare); }; // invoke `checkPassword` on `me` by explicitly setting the `this` context