33일차 TIL : 자바스크립트 심화

변시윤·2022년 12월 2일
0

내일배움캠프 4기

목록 보기
33/131

학습내용

this


'this'란?

실행 컨텍스트에서 현재 객체를 참조하는 키워드. 이때 객체는 함수 호출 방법에 따라 달라진다.


상황별 this

전역 공간

window(브라우저), global(node 환경)등의 전역 객체를 가리킨다. 예를 들어 브라우저 환경의 전역 공간에서 this === windowtrue를 반환한다. 따라서 전역 변수를 선언할 때는 var, let, const 키워드를 사용하지 않아도 된다. 변수가 전역 객체의 프로퍼티로 선언되기 때문이다.

단, this를 사용하는 함수를 일반 함수로 호출하면 this는 전역 객체를 참조한다. 화살표 함수를 사용하면 이를 예방할 수 있다. 화살표 함수에서는 this가 전역 객체를 참조하지 않고 함수가 선언된 곳의 this를 참조한다.

전역 공간(Global Scope)
가장 바깥쪽에 존재하는 영역으로 프로그램이 시작될 때 생성되며, 프로그램이 종료될 때까지 유지된다. 이 영역에 선언된 변수를 전역 변수(Global Variable), 함수를 전역 함수(Global Functino)라고 한다. 전역 변수와 전역 함수는 모든 코드에서 접근 가능하기 때문에 전역 공간은 코드의 모듈성을 해치고, 의존성이 높아진다는 문제가 있다. 그러므로 전역 변수와 전역 함수를 최소화 하고 지역 공간을 활용하는 편이 좋다.

지역 공간(Local Scope)
함수 내에서 선언한 변수와 매개변수들이 포함된 공간으로 함수가 실행될 때 생성되며, 함수가 실행을 완료하면 소멸된다.

function addOne(num) {
  let count = 0;
  return num + 1;
}

위 코드에서 countaddOne 함수의 지역 공간에서 선언되었으므로, addOne이 호출될 때마다 count가 새롭게 생성된다. 즉, 변수는 함수 내부에서만 접근 가능하며 함수 외부에서는 존재하지 않는다.

이처럼 함수 내에서 필요한 데이터를 안전하게 보관하고, 전역 공간을 불필요하게 오염시키지 않아 안정적인 코드 작성이 가능하다.

함수

this가 지정되지 않았으므로 전역 객체 window를 가리킨다. 단, strict mode에서는 thisundefined를 가리킨다.

var func = function (x) {
	console.log(this, x);
};
func(1);

this = window

메서드

주체가 되는 객체를 가리킨다.

var obj = {
	method: func, // 위 함수의 func
};
obj.method(2) // = obj['method'](2)

methodobj에 의해 호출되었으므로 this = obj

함수와 메서드의 차이

  • 함수
    단독 호출 가능 ex) getAge();
  • 메서드
    호출 주체 필요 ex) person.getAge();

메서드 내부 함수

일반 함수와 마찬가지로 전역 객체를 가리킨다. this binding을 결정짓는 요소는 해당 함수를 호출하는 구문 앞에 .[]의 여부다. 메서드 내부인지, 함수 내부인지 등의 주변 환경은 영향을 미치지 않는다.

var obj1 = {
	outer: function() {
    	console.log(this); // obj1
        var innerFunc = function() {
        	console.log(this); // window
        }
        innerFunc();
        
        var obj2 = {
        	innerMethod: innerFunc
        };
        obj2.innerMethod();
    }
};
obj1.outer();
  • 첫 번째 this
    obj1outer를 호출하고 있으므로 this= obj1

  • 두 번째 this
    outer 메서드 내부에 있지만 innerFunc() 함수를 독립적으로 호출하고 있으므로 this= window

+ 메서드 내부 함수에서 this 우회하기

  • 변수 활용

    var = obj1 = {
        outer: function() {
            console.log(this); // obj1
            var innerFunc1 = function() {
                console.log(this); // window
            }
            innerfunc1();
    
            var self = this; // obj1
            var innerFunc2 = function() {
                console.log(self);
            };
            innerFunc2()'
        }
    };
    obj1.outer();

    원래대로라면 innerFunc2() 호출 시 thiswindow를 반환해야하지만, outer에서 받아온 this값을 self라는 변수로 할당했기 때문에 obj1을 반환한다.

  • 화살표 함수

    var obj = {
        outer: function() {
            console.log(this); // obj
            var innerFunc = () => {
                console.log(this); // obj
            };
            innerFunc();
        }
    };
    obj.outer();

    화살표 함수는 this binding 과정을 생략하므롤 상위 메서드의 this값이 유지된다.


콜백 함수 내부 함수

  • setTimeout

    setTimeout(function() { console.log(this) }, 300);

    setTimeout 함수는 this를 지정하지 않기 때문에 window 반환 (정확히는 console.log(this) 함수를 호출하는 과정에서 this가 유실되기 때문)

  • forEach

    [1, 2, 3, 4, 5].forEach(function(x) {
        console.log(this, x);
    });    

    forEach 메서드는 this를 명시할 수도 있지만 아무런 명시가 없을 시에는 window를 반환한다.

  • addEventListner

    document.body.innerHTML += '<button id="a">클릭</button>'
    document.body.querySelector('#a').addEventListener('click', function(e) {
        console.log(this, e);
    });    

    addEventListner 메서드는 스스로의 this를 상속하기 때문에 <button id="a">클릭</button> 반환


생성자 함수

인스턴스(생성자 함수로 만든 객체)를 가리킨다.

var Cat = function(name, age) {
	this.bark = "이얏호응";
    this.name = name;
    this.age = age;
};

var yattong = new Cat('야통', 4) // this = yattong
var mu = new Cat('무', 3), // this = mu



메서드를 활용한 명시적 this binding

call

매개변수를 할당해서 this값을 지정한다.

1️⃣ this값 지정

var func = function(a, b, c) {
	console.log(this, a, b, c);
};

func(1, 2, 3) ➡️ window{...} 1 2 3
func.call({x:1}, 4, 5, 6) ➡️ {x:1} 4 5 6

2️⃣ this값 변경

var obj = {
	 a: 1,
     method: function(x, y) {
     	console.log(this.a, x, y);
    };

obj.method(2, 3) ➡️ 1 2 3
thisobj를 가리키므로 this.aa:1이다.

obj.method.call({a:4}, 5, 6) ➡️ 4 5 6
객체 안에 지정한 a의 값도 call 메서드로 변경 가능


apply

call 메서드와 동일하나 두 번째 인자를 ,가 아닌 [배열]로 구분

func.call({x:1}, 4, 5, 6) = func.aplly({x:1}, [4, 5, 6])


+ call과 aplly 응용

  • 유사 배열 객체(array-like-object)에 배열 메서드 적용

    유사 배열
    배열은 아니지만 배열처럼 동작하는 객체

    var obj = {
        0: 'a',
        1: 'b',
        2: 'c',
        length: 3
    };

    배열과 마찬가지로 length를 갖고 있으며 index가 0부터 시작해서 1씩 증가한다.

    Array.prototype.push.call(obj, 'd');
    console.log(obj);

    { 0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4 };

    var arr = Array.prototype.slice.call(obj);
    console.log(arr);

    ['a', 'b', 'c', 'd']

    slice()
    배열로부터 특정 범위의 값을 복사 후 해당 값들을 모아 새로운 배열로 생성하는 함수. 첫 번째 인자로 시작 index, 두 번째 인자로 종료 index를 받으며 시작부터 종료까지의 값을 복사 후 반환한다.

  • arguments에 배열 메서드 적용

    function a() {
        var argv = Array.prototype.slice.call(arguments);
        argv.forEach(function(arg) {
            console.log(arg);
        });
    }
    a(5,1,2);

    5
    1
    2
    a 함수가 호출될 때 a의 인자를 call 메서드를 통해 넘겨받음

  • NodeList에 배열 메서드 적용

    <div>첫 번째 div</div>
     <div>두 번째 div</div>
     <div>세 번째 div</div>
    var nodeList = document.querySelectorAll('div');
    var nodeArr = Array.prototype.slice.call(nodeList);
    nodeArr.forEach(function(node) {
        console.log(node);
    });    

    <div>첫 번째 div</div>
    <div>두 번째 div</div>
    <div>세 번째 div</div>

profile
개그우먼(개발을 그은성으로 하는 우먼)

0개의 댓글