어제 만난 웨일 확장앱을 개발하면서 만난 이슈는 다음과 같다.
두가지 모두 구글의 도움으로 해결 할 수 있었으나, 아직 자바스크립트가 많이 부족함을 느꼈다. 앞으로 웨일 확장앱 개발을 진행하면서 만난 이슈의 기본 개념에 대해 포스팅을 작성하기로 결심했다. 우선 오늘은 첫번째 이슈였던 바인딩에 관해 알아보자
ES6의 화살표 함수는 this를 자체적으로 바인딩 하지 않는다. 때문에 화살표 함수를 사용하면 별도로 binding을 해주지 않고도 사용가능하다. 아래 예제에는 화살표 함수가 사용되어 포스팅 설명과 틀린 부분이 있을 수 있다. 양해 바란다.
바인딩(Binding)이란 함수 호출과 실제 함수를 연결하는 방법이다. 즉 함수를 호출하는 부분에 함수가 위치한 메모리 번지를 연결시켜 주는 것이다. 자바스크립트에서 함수를 호출 할 때는 암묵적으로 arguments 객체 및 this 변수가 함수 내부로 전달된다. 이에 따라 this에 할당되는 값이 달라지게 되어 많은 개발자들이 혼돈을 겪게 된다. 지금부터 하나씩 알아보자
1. 객체의 메서드 호출 할 때 this 바인딩
var myObject = {
name: 'foo',
sayName: () => {
console.log(this.name);
}
}
var otherObject = {
name: 'bar'
}
otherObject.sayName = myObject.sayName;
myObject.sayName(); // foo
otherObject.sayName(); // bar
2. 함수를 호출 할 때 this 바인딩
var test = 'This is test';
console.log(window.test); // 'This is test'
var sayFoo = () => {
console.log(this.test);
}
sayFoo(); // 'This is test'
var value = 100;
var myObject = {
value : 1,
func1 : () => {
this.value += 1;
console.log('func1() called. this.value : ' + this.value); // 2, 호출한 객체의 this가 바인딩
// func1 내부 함수 func2
func2 = () => {
this.value +=1;
console.log('func2() called. this.value : ' + this.value); // 101, 내부함수로서, 전역객체에 binding 된다.
//func2의 내부 함수 func3
func3 = () => {
this.value += 1;
console.log('func3() called. this.value : ' + this.value); // 102
}
func3();
}
func2();
}
};
myObject.func1();
위 코드에서 내부 함수 호출 패턴을 정의해 놓지 않았기 때문에, 내부 함수들은 함수로 취급되어 this는 전역 객체에 바인딩 된다. 그래서 흔히들 that 변수를 이용해 this값을 저장한다. 아래와 같은 식이다.
var value = 100;
var myObject = {
value : 1,
func1 : () => {
var that = this; // 현재 바인딩 된 this(myObject)를 that에 저장
this.value += 1;
console.log('func1() called. this.value : ' + this.value); // 2,
// func1 내부 함수 func2
func2 = () => {
that.value +=1;
console.log('func2() called. this.value : ' + that.value); // 3
}
func2();
}
};
myObject.func1();
call()
과 apply()
를 통해 명시적으로 this를 바인딩 가능하다. 기본 문법은 아래와 같다.function.apply(thisArg, argArray)
call()
과 apply()
의 기능은 함수 호출이다. thisArg는 this에 바인딩 할 객체, argArray는 함수를 호출 할 때 넘길 인자들의 배열이다.
function Person(name, age){
this.name = name;
this.age = age;
}
var applyPerson = {};
var newPerson = new Person('mike', 24);
Person.apply(applyPerson, ['Jack', 24]);
console.log(applyPerson.name) // Jack
console.log(newPerson.name) // call
whale.tabs.executeScript({
code: `
window.showSubtitle = new ${ShowSubtitle}();
window.showSubtitle.getSubtitles();
`
}, function (result) {
if(result == null)
console.log("자막을 가져오는데 오류가 발생했습니다.");
else
this.transSubtitles(result[0]);
}.bind(this))
};
http://jeonghwan-kim.github.io/2017/10/22/js-context-binding.html
https://preamtree.tistory.com/117
var myObject = {
name: 'foo',
sayName: () => {
console.log(this.name);
}
}
var otherObject = {
name: 'bar'
}
otherObject.sayName = myObject.sayName;
myObject.sayName(); // foo
otherObject.sayName(); // bar
이분분에서 각각 foo, bar가 아닌 undefined가 될것 샅아요 이유는 화살표함수는 렉시컬 바인딩을 하는데 객체 내부에서 바인딩을 보면 this는 윈도우기 때문입니다