[3주차] Javascript 문법 종합반 3주차 강의 내용 정리 (3)

voyager 999·2024년 1월 8일

JavaScript

목록 보기
12/19

this

상황에 따라 달라지는 this

this는 실행 컨텍스트가 생성될 때 결정된다. 이것을 'bind한다'라고 한다.

  • 전역 공간에서 this:
    노드에서는 global 객체, 브라우저에서는 window 객체
  • 함수 vs 메서드:
    함수는 그 자체로 독립적인 기능을 수행하지만, 메서드는 자신을 호출한 대상 객체에 대한 동작을 수행한다.

    메서드는 점(.)이나 대괄호([])로 호출할 수 있다.
함수명(); // 스스로 수행
객체.메서드명(); // 어떤 객체가 메서드를 실행시켜 줘야 함

this의 할당

/** CASE1 : 함수 */
// 호출 주체를 명시할 수 없기 때문에 이 때 this는 전역 객체를 의미한다.

let func = function (x) {
   console.log(this, x);
};
func(1); // Window { ... } 1


/** CASE2 : 메서드 */
// 호출 주체를 명시할 수 있기 때문에 this는 해당 객체(obj)를 의미한다.

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

let obj = {
   method: func,
};
obj.method(2); // { method: f } 2
  • 함수로서 호출할 때 그 함수 내부에서의 this:
    호출 주체가 없다. 즉 this는 지정되지 않는다. 실행 컨텍스트를 활성화할 때 this가 지정되지 않으면 this는 전역 객체를 의미한다.
    함수로서 독립적으로 호출할 때 this는 항상 전역객체를 가리킨다.

  • 메서드 내부함수에서의 this:
    메서드의 내부에 있다고 해도, 함수로서 호출한다면 this는 전역 객체를 의미한다.

this 우회

1. 변수를 활용하는 방법
내부 스코프에 이미 존재하는 this를 별도의 변수(이 경우 self)에 할당하는 방법

var obj1 = {
   outer: function() {
      console.log(this); // (1) outer

	  // AS-IS
      var innerFunc1 = function() {
         console.log(this); // (2) 전역객체
    }
      innerFunc1();
    
      // TO-BE
      ver self = this;
      var innerFunc2 = function() {
         console.log(self); // (3) outer
      };
      innerFunc2();
   }
};

2. 화살표 함수(this를 바인딩 하지 않는 함수)
일반 함수와 화살표 함수의 가장 큰 차이점은, 'this 바인딩 여부'에 있다.

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

obj.outer();

콜백 함수 호출 시 그 함수 내부에서의 this

콜백함수도 함수기 때문에 this는 전역 객체를 호출한다. 단, 콜백함수를 넘겨 받은 함수에서 콜백함수에 별도로 this를 지정한 경우는 예외로 그 대상을 참조한다.

setTimeout함수, forEach 메서드는 콜백 함수를 호출할 때 대상이 될 this를 지정하지 않으므로 this는 곧 전역(global) 객체이다.

addEventLisstner 메서드는 콜백 함수 호출 시 자신의 this를 상속하므로, 이 때 this는 addEventListener의 앞부분이다.

생성자 함수에서의 this

생성자 함수(구체적인 인스턴스를 만들기 위한 일종의 틀)에서의 this는 항상 새로 생성될 인스턴스를 지칭한다.

var Cat = function (name, age) {
   this.bark = '야옹';
   this.name = name;
   this.age = age;
};

var samsaek = new Cat('삼색', 3); // this: samsaek
var tuxedo = new Cat('턱시도', 4); // this: tuxedo

명시적 this 바인딩

1. call()
this가 전역객체를 바라보는 경우, 호출 주체가 있는 경우 모두 call()를 사용해서 명시적 this바인딩이 가능하다.

/** this가 전역객체를 호출하는 경우 */

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

// no binding
func(1, 2, 3); // global, 1 2 3

// 명시적 binding
func.call({ x:1 }, 4, 5, 6}; // { x:1 } 4 5 6



/** this의 호출 주체가 있는 경우 */
var obj = {
   a: 1,
   method: function (x, y) {
      console.log(this, a, x, y);
   }
};

// no binding
// method 함수 안의 this는 항상 obj
obj.method(2, 3); // 1 2 3

// 명시적 binding
obj.method.call({a: 4}, 5, 6); // 4 5 6

2. apply()
call()과 비슷하지만, this 뒤에 오는 매개 변수를 대괄호[]로 묶어준다는 차이점이 있다.

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

// 명시적 binding
obj.method.apply({a: 4}, [5, 6]); // 4 5 6

유사배열객체(array-like object)

유사배열의 조건

  1. 반드시 length가 필요해야 한다.
  2. index 번호가 0부터 시작해서 1씩 증가해야 한다.
  • slice(): 시작 인덱스, 종료 인덱스를 인자로 받아 시작 인덱스부터 종료 인덱스까지 값을 복사하여 새로운 배열로 반환
/** 유사배열 객체 */
// 배열은 아니지만 배열의 형태를 갖추고 있다.
// 배열처럼 .push(), /slice() 같은 배열 메서드를 사용할 수 없다.

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

//그러나 배열 메서드를 쓰는 것'처럼'은 할수 있다.
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']

Array.from 메서드 (ES6)

객체를 배열로 쉽게 바꿔주는 메서드

/** 유사배열 객체 */
var obj = {
   0: 'a',
   1: 'b',
   2: 'c',
   length: 3
};

var arr = Array.from(obj);

console.log(arr); // ['a', 'b', 'c']

call, apply, bind 응용

  • 생성자 함수를 사용할 때 call()를 통해 공통된 부분을 저장해 두고 인스턴스를 생성할 때 불러와서 코드를 좀 더 효율적으로 만들 수 있다.
function Coffee(name, price) {
   this.name = name;
   this.price = price;
}

function Americano(name, price, bean) {
   Coffee.call(this, name, price);
   this.bean = bean;
}

function Latte(name, price, milk) {
   Coffee.call(this, name, price);
   this.milk = milk;
}

var Ame = new Americano("매일 아메리카노", "2100", "과테말라");
var Lte = new Latte("매일 라떼", "2900", "저지방우유");



  • apply()spread operator(...)를 통해 배열 요소들 중 최댓값과 최솟값을 쉽게 찾을 수 있다.
var numbers = [10, 20, 3, 16, 45];

/** 반복문을 활용한 방법 */
var max = min = numbers[0];
numbers.forEach(function(number)) {
   if (number > max) {
      max = number;
   }
   
   if (number < min) {
      min = number;
   }
});
console.log(max, min); // 45 3


/** apply()를 활용한 방법 */
var max1 = Math.max.apply(null, numbers);
var min1 = Math.min.apply(null, numbers);

console.log(max1, min1); // 45 3


/** spread operator를 활용한 방법 */
var max2 = Math.max(...numbers);
ver min2 = Math.min(...numbers);

console.log(max2, min2); // 45 3



  • bind()는 this를 바인딩하는 메서드이다. 즉시 함수를 호출하지는 않는다는 점에서 call(), apply()와 다르다. (해당하는 함수를 바인딩해서 새로운 함수를 리턴하는 형식)
var func = function (a, b, c, d) {
   console.log(this, a, b, c, d);
};

/** 함수에 this를 미리 적용하는 목적 */
var bindFunc1 = func.bind({x: 1});
bundFunc1(5, 6, 7, 8); // {x: 1} 5 6 7 8

/**부분 적용 함수를 만드는 목적 */
var bindFunc2 = func.bind({x: 1}, 4, 5);
bindFunc2(6, 7); // {x: 1} 4 5 6 7



  • bind() 메서드를 사용해서 새로 만든 함수는 'bound'라는 name property를 갖게 된다. -> 추적이 쉬워진다.
var func = function (a, b, c, d) {
   console.log(this, a, b, c, d);
};

/** 함수에 this를 미리 적용하는 목적 */
var bindFunc1 = func.bind({x: 1});

/**부분 적용 함수를 만드는 목적 */
var bindFunc2 = func.bind({x: 1}, 4, 5);

console.log(func.name); // func
console.log(bindFunc1.name); // bound func
console.log(bindFunc2.name); // bound func

1개의 댓글

comment-user-thumbnail
2024년 1월 8일

화이팅!! ㅠㅠ

답글 달기