2024/05/07 자바스크립트 문법 6

YIS·2024년 5월 7일
post-thumbnail

2. 명시적 this 바인딩

자동으로 부여되는 상황별 this의 규칙을 깨고 this에 별도의 값을 저장하는 방법

call 메서드

첫 번째 매개변수에 this로 binding할 객체를 넣어주면 명시적으로 binding할 수 있음.

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

// no binding
func(1, 2, 3); // Window{ ... } 1 2 3

// 명시적 binding
func.call({ x: 1 }, 4, 5, 6); // { x: 1 } 4 5 6 
//첫번째 매개변수에 this바인딩을 할당.

apply 메서드

call 메서드와 같음.
단 this에 binding할 객체는 똑같이 넣어주고 나머지 부분만 배열 형태로 감싸줌

var func = function (a, b, c) {
	console.log(this, a, b, c);
};
func.apply({ 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);
	}
};

obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6
//this 바인딩할당 뒷부분 매개변수들을 []대괄호로 감싸줌

call / apply 메서드 활용

this binding 외에 다른 방법으로도 쓰임.

  • 유사배열객체에 배열 메서드를 사용
    유사배열조건 : 반드시 length가 필요. index번호가 0부터시작해서 1씩 증가
var obj = {
	0: 'a',
	1: 'b',
	2: 'c',
	length: 3
};
Array.prototype.push.call(obj, 'd');
// Array.prototype은 모든 배열이 공통으로 사용할 수 있는 기능(메서드)과 속성을 정의한 곳
//obj 객체에 대해 push 메서드를 호출해서 거기에 'd'를 할당하라는 의미
//call 함수를 사용함으로써 배열이 아닌 객체인 obj에 대해서도 push 메서드를 사용할 수 있음
console.log(obj); // { 0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4 }

var arr = Array.prototype.slice.call(obj,1,4);
console.log(arr); // [ 'b', 'c', 'd' ]
//슬라이스 메서드를 이용해 1번 인덱스부터 4번 인덱스 바로전까지 포함하는 새로운 배열 반환
  • Array.from 메서드
    ES6에 나온 메서드로 call/apply를 통해 this binding을 해서 객체->배열 형변환 하는방법보다
    쉽게 바꿀수 있게 해줌.
// 유사배열
var obj = {
	0: 'a',
	1: 'b',
	2: 'c',
	length: 3
};
// 객체 -> 배열
var arr = Array.from(obj);
console.log(arr); // ['a', 'b', 'c']
  • 생성자 내부에서 다른 생성자 호출
    공통속성이 필요한 부분을 따로 만들어서 필요한 부분에 불러서 사용
function Person(name, gender) {
	this.name = name;
	this.gender = gender;
}
function Student(name, gender, school) {
	Person.call(this, name, gender); // 여기서 this는 student 인스턴스!
	this.school = school;
}
function Employee(name, gender, company) {
	Person.apply(this, [name, gender]); // 여기서 this는 employee 인스턴스!
	this.company = company;
}
var kd = new Student('길동', 'male', '서울대');
var ks = new Employee('길순', 'female', '삼성');
//kd라는 변수에 student라는 생성자함수를 할당함
//Student라는 함수 틀에 '길동', 'male', '서울대'라는 매개변수값을 할당할건데
//student함수안에도 person이라는 생성자함수 틀이 있음. 
//person에 call메서드를 사용해 person내부에서 사용하는 this값이 student를 바라보게 만듬. 
//들어온 인자가 person에서 작업되고 그값을 student에서 뿌려주는거
//그리고 Student와 Employee에서 다른 부분인 school과 company부분만 
//각각 this로 받아서 출력
  • 여러 인수를 묶어 하나의 배열로 전달할 때
//비효율
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);

반복문으로 배열을 돌면서 비교값을 전 인덱스와 비교하면서 그거나 작으면
max,min에 누적저장후 계속 비교하는 로직임. 이걸 좀더 효율적으로 바꾸면

//효율
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
console.log(max, min);
//Math.max(min)은 자바스크립트에 기본제공하는 내장함수. 
//안에 들어온 인자값을 비교후 반환하는데 numbers는 배열이라 배열자체를
//apply(배열값을 받음)를 이용해 비교할수 있음

// 펼치기 연산자(Spread Operation)
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max min);
//배열 형태를 풀어주는 연산자(...) 
//[10, 20, 3, 16, 45] 이 ...numbers를 하면 10, 20, 3, 16, 45이렇게 됨
//바로 각각의 인자들로 값이 들어와서 Math.max(min)으로 비교해서 값 리턴가능

bind 메서드

call,apply와는 다르게 즉시 호출되지 않음.
해당하는 함수를 this.바인딩 해서 새로운 함수를 리턴함. 리턴했을때
받아줄 변수 필요.

  • 특징
    함수에 this를 미리적용
    *부분 적용 함수
    name 프로퍼티
var func = function (a, b, c, d) {
	console.log(this, a, b, c, d);
};
func(1, 2, 3, 4); // window객체

// 함수에 this 미리 적용
var bindFunc1 = func.bind({ x: 1 }); //받아줄 변수 bindFunc1에 할당.
bindFunc1(5, 6, 7, 8); // { x: 1 } 5 6 7 8

// 부분 적용 함수 구현
var bindFunc2 = func.bind({ x: 1 }, 4, 5); // func매개변수 a,b자리에 4,5를 미리 할당

bindFunc2(6, 7); // func c와 d자리에 6,7들어감 { x: 1 } 4 5 6 7 
bindFunc2(8, 9); // func c와 d자리에 8,9들어감 { x: 1 } 4 5 8 9

bind 메서드는 name프로퍼티에 bound라는 접두어가 붙음. 추적하기 용이

var func = function (a, b, c, d) {
	console.log(this, a, b, c, d);
};
var bindFunc = func.bind({ x:1 }, 4, 5);

console.log(func.name); // func
console.log(bindFunc.name); // bound func

상위 컨텍스트의 this를 내부함수나 콜백함수에 전달하기

  • 내부함수

-변수에 직접 this값을 저장후 사용

		...
		...
		var self = this;
		var innerFunc2 = function() {
			console.log(self); 
		};
		innerFunc2();

-call, apply 사용

var obj = {
	outer: function() {
		console.log(this); // outer 메서드를 호출할때 ,this는 호출한 객체인 obj를 가리킴 
		var innerFunc = function () {
			console.log(this);//여기선 전역객체를 . 그런데 밑에서 call
		};

		innerFunc.call(this); // call메서드 사용시 첫번째 인자로 전달된 값이
      //호출할 함수의 this로 설정됨. call(this)는 innerFunc를 호출하면서 
      //outer의 this(obj)를 innerFunc의 this 로 명시적으로 바인딩함.
      //그래서 결과적으로 obj를 가리킴.
	}
};
obj.outer();

-bind를 사용

var obj = {
	outer: function() {
		console.log(this); //outer 를 호출한 객체인 obj
		var innerFunc = function () {
			console.log(this);//잠깐 전역객체
		}.bind(this); // innerFunc에 this를 결합한 새로운 함수를 할당
                     //this는 outer의 this를 가리키고 outer의 this는 obj를 가리킴 
		innerFunc();
	}
};
obj.outer();
  • 콜백함수
    함수가 인자로 전달될때는 this가 전역객체 가리킴.
    bind 이용해 this설정 가능.
var obj = {
	logThis: function () {
		console.log(this); //호출한 객체인 obj를 가리킴.
	},
	logThisLater1: function () {
		setTimeout(this.logThis, 500);//setTimeout 내에서 this.logThis를 직접 전달할 경우
      //setTimeout이 실행될 때 this.logThis가 가리키는건 전역객체
	},
	logThisLater2: function () {
		setTimeout(this.logThis.bind(this), 1000);
      // setTimeout 내부에서 logThis 함수가 호출될 때  
      //.bind(this) 메소드를 사용하여 logThis 함수의 this를 obj 객체에 명시적으로 바인딩
	}
};

obj.logThisLater1(); //전역객체
obj.logThisLater2(); //obj

예외적인 화살표 함수

this를 바인딩하는 과정이 없음
접근하면 스코프체인상 가장 가까운 this에 접근
가장 편리한 방법

var obj = {
	outer: function () {
		console.log(this); //outer를 호출한 obj
		var innerFunc = () => {
			console.log(this);//가장 가까운 스코프 obj를 가리킴.
		};
		innerFunc();
	}
};
obj.outer();
profile
엉덩이가 무거운 사람

0개의 댓글