ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • this / call(), apply(), bind()
    concept/javascript 2020. 4. 14. 18:38

     

    this

     

    => execution context,

       엄밀하게 말해서는 execution context의 구성 요소 중 하나로 함수가 실행되는 동안 이용할 수 있다.

    => 이 execution context는 함수 단위로만 생긴다.

    => 그리고 함수가 호출되었을 때만 생긴다!

     

    => 모든 함수 scope 내에서 자동으로 설정되는 특수한 식별자

     

    간단하게 말해서 현재 실행되고 있는 문맥을 말한다.

     

    5 Patterns of Binding 'this'

     

    1. Global invocation : window

     

    this // global reference
    //-> window

     

     

    2. function invocation : window

     

    function bar() {
    	console.log(this);
    }
    
    bar() // -> window
    window.bar() //이렇게 한거랑 똑같다! 이건 method invocation

     

     

    3. method invocation : parent object

     

    method는 객체에 담긴 함수를 말한다!

    let obj2 = {
    	hello : {
    		fn : function() {
            console.log(this);
        	}
    	}
    }
    
    // this는 hello -> 직계 부모만 가져온다.

     

    var obj = {
    	fn: function(a, b){
    	return this;
    	}
    }
    
    var obj2 = {
    	method: obj.fn
    };
    
    console.log(obj2.method() === obj2); //true
    console.log(obj.fn() === obj); //true
    //-> 실행되는 시점에 있는 부모를 가져와야 한다!

     

     

    4. construction mode (new 연산자로 생성된 function 영역의 this)

     

    function bar() {
    	console.log(this);
    }
    
    var barInstance = new bar(); // bar {}
    function F(v){
    	this.val = v;
    }
    // create new instance of F
    var f = new F('woohoo!')
    
    console.log(f.val); // woohoo!
    console.log(val); // ReferenceError

     

    5. .call(), .apply(), .bind() : call, apply, bind의 첫번째 인자로 명시된 객체

     

    .call(첫번째 인자, 두번째 인자) / .apply(첫번째 인자, 두번째 인자)

     

    여기서 첫번째 인자는 무조건 this 이고

    두번째 인자는 call 앞에 나오는 function의 인자로 들어간다.

    call을 하면 함수를 실행한다. (bind를 하면 실행되기 전의 함수를 리턴한다)

     

    function identify() {
    	return this.name.toUpperCase();
    }
    
    function speak() {
    	var greeting = 'Hello, I am' + identify.call(this);
        console.log(greeting);
    }
    
    var me = { name: 'Kyle' };
    var you = { name: 'Reader' };
    
    identify.call(me); // KYLE
    identify.call(you); // READER
    speak.call(me); // Hello, I'm KYLE
    speak.call(you); // Hello, I'm READER

     

    call과 apply의 차이점?

    var add = function (x, y) {
    	this.val = x + y;
    }
    
    var obj = {
    	val: 0
    };
    
    add.apply(obj, [2, 8]);
    console.log(obj.val); // 10 -> apply는 argument를 배열로 넣어줘야 한다.
    add.call(obj, 2, 8);
    console.log(obj.val) // 10 -> call은 그냥 콤마로 구분해서 넣어주면 된다.

     

    call 또는 apply를 이용해 주체가 되는 인스턴스와 메소드의 순서를 바꿀 수 있다.

    주어와 동사가 바뀌는 것으로 이해하면 쉽다!

    function moreThanFive(element){
    	return element.length > 5;
    }
    
    let arr = ['code', 'states'];
    arr.filter(moreThanFive);
    //['states']
    
    Array.prototype.filter.call(arr, moreThanFive);
    //['states']

     

    call 은 이런 경우에 유용하게 사용할 수 있다!

    (유사배열이기 때문에 배열메소드를 못 쓰는 경우)

    let list = document.querySelectorAll('li')
    Array.prototype.filter.call(list, function(elementLi){
    	return elementLi.classList.contains('selected');
    });

     

    bind case: 특정 함수가 this 값을 바꿔버리는 경우

    setTimeout의 경우에는 첫번째 인자에 들어가는 함수에서 this는 무조건 window로 들어간다.

    여기서 this를 지정해줘야할 경우 bind를 사용할 필요가 생긴다!

    왜냐면 bind는 함수의 실행을 리턴하는 것이 아니라 this값이 바인딩 된 함수 자체를 리턴하기 때문!

    (setTimeout의 콜백함수는 실행되기 전 함수가 들어가야 한다는 것을 전제하에 설명한다.)

    function Box(w, h){
    	this.width = w;
        this.height = h;
        
        this.getArea = function() {
        	return this.width * this.height;
        }
        
        this.printArea = function() {
        	console.log(this.getArea());
        }
    }
    
    let b = new Box(100, 50);
    b.printArea(); // 5000
    
    setTimeout(b.printArea.bind(b), 2000); // 2초 후 b.printArea를 실행

     

    setTimeout 참고!

    let func = function(){
    	console.log(‘test’)
    }
    
    setTimeout(func(), 1000); -> 땡!
    setTimeout(func, 1000); -> 딩동댕!
    
    //setTimeout의 첫번째 인자는 함수 자체를 넣어줘야 한다

     

    bind case: currying

    인자 여러개를 받는 함수를 인자 하나를 받는 함수로 바꾸는 방법도 있다!

    var toBeCurried = function (a, b) {
        console.log('a': + a + ' b: ' + b);
    };
    var curried = toBeCurred.bind(null, 1);
    curried(2); // a: 1 b: 2

     

     

    this 를 확실히 알았는지 테스트!

     

    let fn = function (one, two) {
      console.log(this, one, two);
    };
    
    let r = {r:1};
    let g = {g:1};
    let b = {b:1};
    let y = {y:1};
    
    r.method = fn;

     

    다음과 같이 호출할 때, 각 케이스에서 this의 값은?

    // (1)
    r.method(g,b);
    
    // (2)
    fn(g,b);
    
    // (3)
    fn.call(r,g,b);
    
    // (4)
    r.method.call(y,g,b)
    더보기

     

    (1) r

    (2) window

    (3) r

    (4) y

     

     

    댓글

Designed by Tistory.