JS의 화살표 기능을 사용하는 this

독자 여러분, 항상 자바스크립트에서 가장 혼란스러운 주제 중 하나였습니다. Java와 같은 프로그래밍 언어에 대한 사전 지식이 있는 경우 이를 이해하는 것이 훨씬 더 어려운 작업이 될 것입니다. 전혀 겹치지 않습니다.

다양한 다른 기능 및 개선 사항과 함께 ES6는 화살표 기능을 가져왔고 화살표 기능의 도입과 함께 이것의 개념은 몇 가지 더 조정되기 시작했습니다. 화살표 함수의 개념과 동작을 이해하려면 이에 대한 사전 이해가 반드시 필요합니다. 따라서 여기에서 잠시 멈추고 이에 대해 이해한 다음 주제로 다시 이동하십시오.

목차:


  • What are arrow functions?

  • Understanding this behaviour with arrow functions
  • 정상신고시
  • 전역 개체 내부에 정의됨
  • 개체 내부의 중첩된 함수 호출에서
  • 전역 함수가 개체에 바인딩됨

  • Conclusion

  • 화살표 기능이란 무엇입니까?

    Along with various other features, ES6 brought arrow functions with it too. They are newer, easier, and much cleaner ways of writing a function. They reduce the lines of code required to declare a function and come with small differences from the normal function declaration.
    Let's compare the normal and arrow function declaration syntax first.

     

    //normal function
    function foo1(){
        return null
    }
    //arrow functions
    const foo2 = () => {
        return null
    }
    //this can further be written in much simpler way
    const foo = () => return null
    

    As we see, arrow functions have much simpler syntax but the major difference is that arrow functions don't create their own binding but take up the binding of their parent object i.e. they inherit it from the parent scope (remember, the parent should be a non-function). To make it simpler, the arrow functions follow the same this behaviour as it is in their parent. 
    For normal functions, it totally depends on how and where they are called but for arrow functions, it depends on where they have been defined. In the above example, if we console this inside both the functions then both this will have a global object in them but the reason is quite different. Let's explore the same in next section.

    화살표 함수로 이 동작 이해하기

    this behaviour in arrow function can vary in different scenarios so let's break it into smaller parts and look through them.

    • In normal declaration
    //normal function
    function foo1(){
        console.log(this)
    }
    //with arrow functions
    const foo2 = () => {
        console.log(this)
    }
    
    foo1()
    foo2()
    

    We saw in the above scenario, both consoles will print a global object(window object in case of browsers). Function foo1() is declared in a global context and is called in a global context, which is a normal function call. This means that the object calling foo1() is a global/window object(foo1() can also be called as a window.foo1()) and therefore, this in having a value of the global object and hence, for a normal function call, this always points to object calling that function. Whereas, foo2 has been declared in a global context whose this always points to a global object and hence, in arrow function this takes up the value of its parent binding, here global context and points to global/window object.

    • Defined inside a global object
    //normal function
    const obj1 = {
    foo1 : function(){
            console.log(this)
         }
    }
    //with arrow functions
    const obj2 = {
    foo2 : () => {
            console.log(this)
         }
    }
    
    obj1.foo1()
    obj2.foo2()
    

    To call the normal function(foo1) inside obj1, we need to first access obj1 and then call foo1 through it. Hence, foo1 is not a normal function call and it has to be called through obj1. obj1 is an object and has created its own binding(this) and calling foo1 through obj1 makes this inside obj1 to have all properties of obj1 only and not global/window object. Whereas, if we look at obj2 and foo2, then even though foo2 is declared as a key inside obj2 but still it will have a value of this inherited from its lexical scope i.e. obj2 because as defined earlier, arrow functions inherit this property from their parent and here obj2, which is parent object to foo2 has been declared in global/window context which has this binding to global/window context and therefore, passes same this (global/window) to foo2.

    • In nested function call inside an object
    //normal function call inside a method
    const obj1 = {
            foo1 : function(){
                    function foo2(){
                            console.log(this)
                    }
                    foo2()
            }
    }
    obj1.foo1()
    //arrow function call inside a method
    const obj2 = {
            foo3 : function(){
                    const foo4 = () =>{
                            console.log(this)
                    }
                    foo4()
            }
    }
    obj2.foo3()
    

    If you look closer at the code, then you can guess the output for both consoles as it has already been explained in the above two points. If you have taken a guess and it comes to be the same as what we will discuss, then congratulations to you. 

    So, in foo2 the console will print the global/window object and the reason is in the definition above, any normal function call will always point its this to the global/window object. Here, foo1 is a method to obj1 but foo2 is a normal function declared inside this method and hence this pointing to global/window object. In the second scenario, foo4 is an arrow function that takes up the this from its lexical scope so here, foo4 is lexically scoped to foo3, and foo3's this is pointing to obj2 object, and hence foo4 will also point to obj2.

    Here comes an interesting question. What if, foo3 is assigned with an arrow function instead of a normal function?

    const obj2 = {
            foo3 : () => {
                    const foo4 = () =>{
                            console.log(this)
                    }
                    foo4()
            }
    }
    obj2.foo3()
    

    In this case, it is certain that foo4 will always take up its this value from the parent non-function which in this case is obj2, and since, obj2 is a global object whose binding is to a global object and hence foo4's this will also point to global/window object. So, we can see a drastic change in the behaviour of functions depending if they are normal or arrow functions.

    • Global functions bind to an object
    //normal function
    function foo1(){
            console.log(this)
    }
    const obj1 = {
            name: 'Akansh'
    }
    const foo2 = foo1.bind(obj1)
    foo2()
    
    //arrow function
    const foo3 = () => {
            console.log(this)
    }
    const obj2 = {
            name: 'Akansh'
    }
    const foo4 = foo3.bind(obj2)
    foo4()
    

    The given examples are no different from what we have seen earlier in the above examples. The only difference is that a global function is created which is now bound to another object and hence, the functions will now be treated as they were declared inside the object.

    foo2 carries foo1 bind to obj1 and hence, calling foo2() is just like calling obj1.foo1()(if foo1 was declared inside obj1) and therefore, foo2 will have its this pointing to obj1 only. Similarly, foo4 carries foo3 bind to obj2 but here foo4 this points to global/window object because we now know that arrow function inside the object will have this pointing to object's binding and here its global/window object.

    결론

    For a normal function call, this will always point to global/window object. A normal function defined inside an object will always takes up this from the object written on adjacent left in the dot notation. Example:

    const obj = {
        foo : function(){
             console.log(this)
        }
    }
    obj.foo()
    //here, obj is the object calling foo and is on the adjacent left while writing in dot notation
    

    For arrow function, the simplest explanation will be, this will always inherit binding from its non-functional parent. If defined in global context, then this in arrow function points to global/window object only.

    I believe that the explanation was of some help to you and provided some value. If there is something I might have missed or you would like me to address or if there are some suggestions, feel free to comment and reach out.

    좋은 웹페이지 즐겨찾기