Re-creating the Lodash Library: _.dropWhile


#1

https://www.codecademy.com/paths/web-development/tracks/web-dev-js-arrays-loops-objects/modules/pjs-javascript-capstone/projects/lodash

I’m working on the _.dropWhile method near the end of the Lodash project. I’ve been working on it for a day now and it’s not productive, I’m stuck. I’ve tried about 100 different approaches. Please help, here’s my latest code:

_.dropWhile = (array, predicate) => {

cb = (element, index) => {
!(predicate(element, index, array));
return index;
};

let dropNumber = array.findIndex(cb);

let droppedArray = this.drop(array, dropNumber);

return droppedArray;
};

The instructions say this:
37.

Implement : Let’s implement our game plan in code.

  1. Add a method to our _ object called dropWhile .
  2. Add two parameters to this method: array and predicate .
  3. Within the method, create a new variable called dropNumber and set its value equal to the return value of a call to findIndex on array .
  4. Pass an anonymous callback function to findIndex that takes two arguments: element and index .
  5. Within the callback function, return the negated return value of predicate called with element , index , and array . We negate the value (use ! ) since we are looking to drop elements until the predicate returns a falsy value. However, .findIndex() is looking for the first truthy value. So, we make every truthy value falsy and vice versa to get the value we are looking for.
  6. After the entire dropNumber declaration, create a new variable called droppedArray and set its value to the return value of this.drop() called with dropNumber . We are using this since .drop() is a method on the _ object which is the current object we are working from, and therefore the current value of this . Calling _.drop() would also have worked but is a less common practice.
  7. Return droppedArray from the method.

#2

Recall that we are writing methods in the _ object.

_.dropWhile = () => {};

vs.

dropWhile () {},

#3

Wow, thanks for clarifying. That solved the problem, writing them using method notation. I had done the entire project using function notation and it passed all the tests up to that point, only failing once _.dropWhile needed to use the this.drop method, and the error message would say 'this.drop is not a function'. I also started the code with const _ = {}; and then added each function/method outside of the object's curly braces by using _.methodName = () => {...}; (terminated with semicolons not commas) which successfully added the functions into the object. Is that aspect of what I did considered acceptable practice? (That is, adding items into the object using _.itemName notation, outside of the object's curly braces).

I am still confused about the difference between using function notation vs. using method notation. I researched it online but I still don't really understand the resulting difference between a function and a method, and why my program failed only in certain ways when written with function notation. Your thoughts?


#4

Hopefully your research found that we cannot use this in an arrow function? And that this will refer to the window object when there is no other context in an ordinary function?

We cannot use arrow functions as methods of an object. The old way to define a method in JS was,

    var obj = {
        a: 6,
        b: 7,
        c: function () {
            return this.a * this.b;
        }
    };
    console.log(obj.c());    // 42

The new syntax takes methods from being an anonymous value of a property to being a full-fledged function, of sorts.

var obj = {
    a: 6,
    b: 7,
    c () {
        return this.a * this.b;
    }
};
console.log(obj.c());    // 42

Here’s where it begins to get weird, but the logic is all there…

var obj = {
    a: 6,
    b: 7,
    _c () {
        return this.a * this.b;
    },
    get c () {
        return this._c();
    }
};
console.log(obj.c));    // 42

That covers methods until we get to classes, but you’ll discover they are much the same. The only thing that changes is the context. Our object above is a single entity. If we wish to replicate this N times, then we make it into a class and spin off as any many clones (instances) as we like. That’s coming in later lessons.

Functions are ojbects too, which means a method is an object. That makes sense considering the way we work with them in both the old and the new syntax. The biggest difference between a function and a method is the execution context.

An object has its own reserved namespace which is its own context. Within that context we may define properties (attributes) and behaviors (methods) that apply only to that object. This gives us what we have above.

Now when we think of functions as methods of the window object it puts them into the same light as object methods described above. The exception here is that we do not need to call them on an object. The ‘window’ object is implicit.

function foo() {
    console.log("Ah, foobar!")
}
window.foo();    // Ah, foobar!

Functions in other words do not need an object instance to call them, just an identifier and zero or more arguments. Here is where another distinction can be made… this and its close association with methods. Since they are in the context of the object, many methods do not require arguments but draw their data from the object’s own namespace, by the given name, this.

We do not have a mechanism of this nature in a function unless we are referring to window attrbutes, which as globals are accessible by name. Again, no dot syntax. That’s sort of what it really boils down to, isn’t it?

Some TL; DR is bound to come about on some questions. I hope I haven’t gone around the field too many times in this reply.

a = 6;
b = 7;
c = function () {
    return this.a * this.b;
}
console.log(c());           // 42
console.log(this.c());      // 42
console.log(window.c());    // 42
 > c = function () {
       return `${this.a * this.b}, ${a * b}`;
   }
<- ƒ () {
       return `${this.a * this.b}, ${a * b}`;
   }
 > c()
<- "42, 42"
 > this.c()
<- "42, 42"
 > window.c()
<- "42, 42"
 > 

#5

Thank you VERY much! That hugely clarifies a topic that was very murky for me, even after a fair amount of research and quite a few lessons. Very clear explanation, much appreciated.

Part of the reason I spent so much time on that Lodash problem (aside from being a beginner programmer) is because this code:

objectName = {};

objectName.functionName = () => {
console.log(‘Hello’);
};

objectName.functionName();

runs, and it successfully puts these functions into the object. But like you said, arrow notation won’t work inside the curly braces of the object, and this.functionName fails when it’s done in this way. So the original (incorrect) way I did it didn’t get rejected by the compiler and would run successfully in all of the other cases up to that point, so I spent ages fiddling around with it without the basic understanding needed to solve the issue. Lesson learned. And I learned a lot by going through this mistake. Thanks again for your assistance!


#6

Which is lesson learned. Kudos.