theonlychase
10/8/2018 - 2:35 AM

"this", call, bind, and apply

Definitions and examples of each

1. "this"
    - The this keyword allows you to reuse functions with different contexts.
    - The “this” keyword allows you to decide which object should be focal when invoking a function or a method. 

2. How to tell what "this" is referencing?

    1. Where is the function being invoked? The ONLY way you can tell what "this" is is by looking where the function using "this" was invoked. 

3. Rules for finding out what "this" is referencing

    1. Implicit Binding
    
        - look to the left of the dot when the function is invoked to find the object that "this" is referencing. 
        - About 80% of the time, implicit binding will tell you what "this" is referencing. 
        
        const user = {
            name: 'Tyler',
            age: 27,
            greet() {
                alert(`Hello, my name is ${this.name}`)
            },
            mother: {
                name: 'Stacey',
                greet() {
                alert(`Hello, my name is ${this.name}`)
                }
            }
        }
        user.greet() // Tyler
        user.mother.greet() // Stacey

    2. Explicit Binding
    
        1. call() Method
        
        function greet () {
            alert(`Hello, my name is ${this.name}`)
        }
        const user = {
            name: 'Tyler',
            age: 27,
        }
        - user does not have a greet method this time. 
        - In this case, we use "call", which is a method on every function that allows you to invoke the function specifying in what context the function will be invoked. 
        - Here, we can invoke greet in the context user
            greet.call(user);
        - the first argument you pass into call() will be what "this" refers to. ALWAYS the first argument refers to "this"
        
        2. apply() Method
        
            - Does the exact same thing as call, but allows you to pass in a single array of arguments and it will spread each element in the array as arguments to the function
            
            function greet (l1, l2, l3) {
                alert(
                    `Hello, my name is ${this.name} and I know ${l1}, ${l2}, and ${l3}`
                )
            }
            const user = {
                name: 'Tyler',
                age: 27,
            }
            const languages = ['JavaScript', 'Ruby', 'Python'];
            greet.call(user, languages[0], languages[1], languages[2]);
            greet.apply(user, languages);
            
        3. bind() Method
        
            - Exact same thing as call, but instead of immediately invoking the function, it';; return a new function trhat you can invoke at a later time
                const newFn = greet.bind(user, languages[0], languages[1], languages[2])
                newFn() // alerts "Hello, my name is Tyler and I know JavaScript, Ruby, and Python"
                
        4. "new" Binding
        
            - Whenever you invoke a function with "new" keyword, the JS interpretor will create a brand new object for you and call it "this".
            
        5. Lexical Binding
        
            - "this" is determined how you would expect, following normal variable lookup rules.
                const user = {
                    name: 'Tyler',
                    age: 27,
                    languages: ['JavaScript', 'Ruby', 'Python'],
                    greet() {
                        const hello = `Hello, my name is ${this.name} and I know`

                        const langs = this.languages.reduce(function (str, lang, i) {
                        if (i === this.languages.length - 1) {
                            return `${str} and ${lang}.`
                        }

                        return `${str} ${lang},`
                        }.bind(this), ""); // without binding "this" here, .length of undefined error occurs. 

                        alert(hello + langs)
                    }
                }
                user.greet();

- So putting all of our rules into practice, whenever I see the this keyword inside of a function, these are the steps I take in order to figure out what it’s referencing.

1. Look to where the function was invoked.
2. Is there an object to the left of the dot? If so, that’s what the “this” keyword is referencing. If not, continue to #3.
3. Was the function invoked with “call”, “apply”, or “bind”? If so, it’ll explicitly state what the “this” keyword is referencing. If not, continue to #4.
4. Was the function invoked using the “new” keyword? If so, the “this” keyword is referencing the newly created object that was made by the JavaScript interpretor. If not, continue to #5.
5. Is “this” inside of an arrow function? If so, its reference may be found lexically in the enclosing (parent) scope. If not, continue to #6.
6. Are you in “strict mode”? If yes, the “this” keyword is undefined. If not, continue to #6.
7. JavaScript is weird. “this” is referencing the “window” object.