이력
- 2022.03.19 8절까지 포스팅
- 2022.03.20 15절까지 포스팅
모든 내용을 상세히 담으려 하지 않았습니다.
제가 모르는 부분이나, “이런 것도 있었어?” 하는 부분, 중요하다고 생각되는 부분,
다시 한번 되새기고 싶은 부분만 기록했습니다.
읽어주셔서 감사합니다.
27.1 this와 실행 컨텍스트#
- 호출한 함수 앞에 작성한 오브젝트를 TBC가 참조하며, this는 TBC를 참조합니다.
1
2
3
4
5
6
7
8
| var sports = {
member: 11,
soccer: function() {
debugger;
return this.member;
}
};
sports.soccer();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| soccer() 호출시의 EC를 형상화 하면 아래와 같습니다.
EC: {
LEC: {
LE: {
ER: {
DER: {}
},
OLER: 글로벌 환경
}
},
VEC: LEC와 동일,
TBC: {
member: 11,
soccer: function() {return this.member}
}
}
|
27.2 this와 글로벌 오브젝트#
- 글로벌 오브젝트에서 this는 항상 글로벌 오브젝트를 참조합니다.
1
2
3
4
5
| price = 200;
var globalPractice = this.price;
this.qty = 123;
js.log(this === window);
js.log(window.qty);
|
- 첫 번째 줄의 코드를 실행하기전에 글로벌 실행 컨텍스트의 TBC에 글로벌 오브젝트를 설정합니다.
- var globalPractice에서 var 키워드를 사용했지만 EC의 초기화 단계에서 글로벌 실행 컨텍스트의 OER에 globalPrice를 설정한 후, 실행단계에서 값을 할당하므로 글로벌 오브젝트에서 설정하는 것과 같습니다.
27.3 strict 모드에서 this와 글로벌 오브젝트#
1
2
3
4
5
6
7
8
9
10
| function music() {
"use strict";
debugger;
return this;
}
js.log(music() === undefined);
// true
js.log(window.music() === window);
// true
|
- music()과 같이 함수 앞에 오브젝트를 작성하지 않고 함수를 호출하면 글로벌 오브젝트를 생략한 것으로 간주합니다. 반면 strict 모드는 글로벌 오브젝트로 간주하지 않고 undefined를 TBC에 설정합니다.
27.4 this 범위#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| var sports = {
member: 111,
get: function() {
var member = 777;
var result = this === sports.get;
debugger;
js.log(result);
// false
js.log(this.member === 111);
// true
// this의 member는 111 이다.
}
}
|
27.5 this와 빌트인 오브젝트#
1
2
3
4
5
6
7
8
9
10
| String.prototype.calcValue = function() {
var total = 0; values = this.split('');
debugger;
values.forEach(function(value) {
total += Number(value);
}, this);
return total;
}
var result = '123'.calcValue();
js.log(result)
|
- 함수 앞에 문자열을 작성하면 타입이 String이므로 this가 String 오브젝트를 참조합니다. 문자열 이외의 숫자, 배열도 마찬가지로 함수 앞에 작성한 값이 오브젝트로 변환될 수 있어야 하며 변환된 오브젝트에 함수가 존재해야 합니다.
- String 오브젝트의 prototype에 calcValue 메소드를 연결합니다. 빌트인 오브젝트에 네이티브 이외의 메소드를 연결하는 것은 바람직하지 않지만 fallback 메소드를 작성할 때 유용합니다.
- 네이티브 메소드를 호출하면 스택에 EC가 표시되지 않지만, 네이티브가 아닌 메소드는 EC가 표시됩니다.
- “this: String"은 this가 String 오브젝트를 참조하는 것은 의미합니다. __proto__에 빌트인 String 오브젝트의 prototype에 연결된 프로퍼티로 인스턴스를 생성하여 첨부했습니다. String 인스턴스를 생성한 것입니다.
- 생성한 String 인스턴스를 this가 참조합니다. js 엔진이 String 인스턴스를 생성하면서 파라미터로 받은 “123"을 프리미티브 값으로 설정합니다. 생성한 인스턴스를 지정하면 프리미티브 값이 반환되듯이 this를 지정하면 생성한 String 인스턴스의 프리미티브 값인 “123"이 반환됩니다.
27.6 this와 호출 오브젝트#
1
2
3
4
5
6
7
8
9
10
11
12
13
| var sports = {
value: 123,
soccer: {
value: 456,
get: function() {
js.log(this === sports.soccer);
js.log(this.value);
}
}
};
sports.soccer.get()
// true
// 456
|
1
2
3
4
5
6
7
8
9
10
| var sports = {
value: 123,
get: function() {
js.log(this === window);
js.log(this.value);
}
};
var comp = sports.get;
comp();
// 오브젝트를 지정하지 않고 호출했으므로 TBC는 글로벌 오브젝트가 된다.
|
1
2
3
4
5
6
7
8
9
10
11
| function get() {
js.log('global');
}
var sports = function() {
function get() { //함수 선언문이므로 초기화 단계에서 DER에 설정됨
js.log('sports');
};
this.get();
get(); // DER의 get을 호출합니다.
}
sports();
|
27.7 this와 인스턴스#
- this를 사용하는 또 하나의 목적이 new 연산자로 생성한 인스턴스마다 값을 유지하기 위해입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| var sales = {};
sales.Book = function(option) {
debugger;
this.options = options;
}
sales.Book.prototype = {
getValue: function() {
debugger;
return this.options;
},
getFirst: function() {
return this.option + 200;
}
}
var obj = new sales.Book(100);
obj.getValue();
|
- this: sales.Book 에서 볼 수 있듯이 this가 sales.Book 오브젝트를 참조하고 있습니다.
- 생성자 함수가 호출되면 엔진은 함수를 실행하기 전에 새로운 인스턴스를 생성하고 생성한 인스턴스를 TBC에 할당합니다.
27.8 new 연산자와 오브젝트 반환#
- 생성자 함수에 return 문을 작성하면 표현식의 평가결과에 따라 인스턴스가 반환되지 않을수도 있습니다.
1
2
3
4
5
6
7
8
9
| var title = function() {
return {value: 123};
}
title.prototype = {
getValue: function(){}
}
var obj = new title();
js.log(obj.value);
// 123
|
1
2
3
4
5
6
7
8
9
10
| var music = function(){
return 123; // 없는 것과 같습니다.
}
music prototype.getValue = function() {
return 456;
}
var obj = new music();
debugger;
js.log(obj.getValue());
// 456
|
- 평가한 값이 오브젝트가 아니면 생성한 인스턴스를 반환합니다.
27.9 this의 주된 목적#
- new 연산자와 생성자 함수를 이용해 인스턴스를 생성하는 목적은 this를 이용해 인스턴스마다 다른 값을 설정하기 위함입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| var title = function(option) {
this.option = option;
}
title.prototype = {
getValue: function() {
return this.option
}
}
var one = new title(100);
var two = new title([200,300]);
one.option = 77;
js.log(one.getValue());
js.log(two.getValue());
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| 1. new title(100); 문장을 평가합니다.
2. 평가한 Function 오브젝트에 [[Constructor]] 존재 여부를 체크합니다.
- 존재하지 않으면 TypeError를 발생시키고 아래 처리를 하지 않습니다.
3. 평가한 Function 오브젝트의 [[Constructor]]를 메소드로 하여 호출합니다.
- 생성자 함수의 파라미터 값을 100을 파라미터로 넘겨줍니다.
4. 새로운 Object를 생성합니다.
5. title Function 오브젝트의 [[Prototype]]을 생성한 인스턴스의 __proto__에 설정합니다.
6. 중략
7. title Function 오브젝트의 [[Call]]을 호출합니다.
8. EC를 생성하고 파라미터 값을 갖고 EC로 이동합니다.
- 파라미터 값 순서: 생성한 인스턴스, 파라미터 값 100, 함수 코드 [[Code]]
9. 중략
10. TBC에 파라미터로 받은 생성한 인스턴스를 설정합니다.
11. 실행 단계에서 this.option = option; 문장을 실행합니다.
12. 중략
13. 생성한 인스턴스를 반환합니다.
|
27.10 call()과 this#
- call 메소드의 첫 번째 파라미터에 작성한 오브젝트를 this가 참조합니다.
1
2
3
4
5
6
7
| var value = 100;
function get(one) {
return one + this.value;
}
var result = get.call(this, 50);
js.log(result);
// 150
|
- get 함수 앞에 오브젝트를 작성하지 않았으므로 글로벌 오브젝트의 get 함수가 호출됩니다.
1
2
3
4
5
6
7
| var get = function(value) {
return this.base * this.rate + value;
}
var result = get.call({base: 20, rate: 30}, 50);
// this 대신 오브젝트를 지정할 수 있다.
js.log(result);
// 650
|
1
2
3
4
5
6
7
8
| var get = function() {
debugger;
return this.valueOf();
}
var result = get.call(123);
// 숫자를 지정하면 데이터 타입에 해당하는 오브젝트(인스턴스)로 변환합니다.
js.log(result)
// 123
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| var sports = {
value: 123,
soccer: {
value: 456,
get: function() {
return this.value;
}
}
};
js.log(sports.soccer.get.call(sports));
// 123
js.log(sports.soccer.get.call(sports.soccer));
// 456
// 오브젝트를 변경하여 호출해 결과를 바꿀 수 있다.
|
27.11 apply()와 this#
- 두 번째 파라미터를 배열로 작성하는 것이 call과 다른 점입니다. call과 달리 파라미터 수가 동적일 때 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
| function get() {
var list = arguments;
debugger;
for (var k = 0; k < list.length; k++) {
js.log(lisk[k] + this[k]);
}
}
get.apply({0: 50, 1: 60, 2: 70}, [10, 20, 30]);
// 60
// 80
// 100
|
1
2
3
4
5
| function get(one, two) {
js.log(one + two + arguments[2]);
}
get.apply(this, [10, 20, 50]);
// 80
|
27.12 bind()와 this#
- 함수를 호출하면 바로 실행되지만 bind 메소드 Function 오브젝트를 생성하여 반환합니다. bind 메소드를 새로운 Function 오브젝트를 생성하는 단계와 생성한 Function 오브젝트를 호출하는 단계로 나눕니다.
1
2
3
4
5
6
7
8
9
10
11
12
| var bonus = {
value: 123,
get: function() {
return this.value;
}
};
js.log(bonus.get());
var fnObj = bonus.get.bind({value: 456});
js.log(fnObj());
// 123
// 456
|
- bonus.get.bind() 형태에서 bind 메소드가 호출되려면 bonus.get이 오브젝트이어야 합니다. 그런데 함수입니다. 이때 자바스크립트의 묘미가 발휘됩니다. “abc”.charAt()에서 “abc"가 문자열이므로 String 오브젝트의 charAt() 메소드가 호출되듯이 bonus.get이 함수이므로 Function 오브젝트의 bind()메소드가 호출됩니다. bonus.get을 호출할 함수로 사용하기 위해 Function 오브젝트를 생성하면서 bonus.get을 [[TargetFunction]]에 저장합니다.
- bonus.get 함수를 연결하여 호출하지 않고 Function 오브젝트를 생성하여 반환하므로 this가 참조하는 오브젝트를 생성한 Function 오브젝트의 [[BoundThis]]에 저장합니다. 두 번째 파라미터를 [[BoundArguments]]에 저장합니다.
- fnObj() 형태로 호출하면 Funtion 오브젝트의 [[TargetFunction]]에 저장된 bonus.get 함수가 호출됩니다. bind() 메소드의 첫 번째 파라미터를 this가 참조하며 Function 오브젝트의 [[BoundThis]]에 설정되어 있습니다. this.value로 값을 반환할 때 [[BoundThis]]를 사용합니다.
1
2
3
4
5
6
7
| var bonus = {
get: function() {
return Array.prototype.slice.call(arguments);
}
};
var fnObj = bonus.get.bind({value: 10}, 20, 30);
js.log(fnObj(40, 50));
|
27.13 bind() 엔진 처리#
1
2
3
4
5
6
7
8
9
| var sports = {
get: function(one) {
var args = arguments;
return this.value + args[0] + args[1] + args[2];
}
};
var fnObj = sports.get.bind({value: 123}, 'soccer', '456');
debugger;
js.log(fnObj('swim'));
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| 1. bind 메소드를 호출합니다.
2. sports.get.bind()에서 sports.get의 호출 가능 여부를 체크합니다.
- bind 메소드 앞에 Function 오브젝트를 지정해야 합니다.
- 호출할 수 없는 상태이면 TypeError를 발생시키고 아래를 처리하지 않습니다.
3. 새로운 Function 오브젝트를 생성합니다.
4. bind 메소드 앞에 작성한 함수를 fnObj의 [[TargetFunction]]에 설정합니다.
5. bind 메소드의 첫 번째 파라미터 fnObj의 [[BoundThis]]에 설정합니다.
6. bind 메소드의 두 번째 이후의 모든 파라미터를 fnObj의 [[BoundArgs]]에 설정합니다.
7. fnObj의 [[Call]]을 설정합니다.
- fnObj()를 호출하면 [[Call]]에 설정된 함수를 호출합니다. [[Call]] 함수에 세 개의 target,
boundThis, boundArgs 프로퍼티가 있으며 아래와 같이 설정한 후 실행합니다.
1) target에 [[TargetFunction]] 값을 설정합니다.
2) boundThis에 [[BoundThis]] 값을 설정합니다.
3) boundArgs에 [[BoundArgs]]에 값을 설정합니다.
8. 생성한 Function 오브젝트를 반환하여 fnObj에 할당합니다.
9. fnObj를 호출합니다.
|
27.14 bind()와 click 이벤트 바인딩#
- bind 메소드를 사용하지 않고 DOM 메소드인 addEventListener(‘click’, show, false)로 이벤트 타입과 이벤트 핸들러를 작성하면 this를 지정하는 파라미터가 없으므로 this를 잊어버리게 됩니다. 따라서 this를 받을 수 있도록 사전 처리를 해야합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <body>
<button id='clickID'>클릭하세요</button>
</body>
<script>
window.onload = function() {
var element = documents.getElementById('clickID');
element.onclick = show.bind(sports, element);
}
var sports = {
value: 123
};
function show(element, event) {
debugger;
js.log(element.textContent);
// 클릭하세요
js.log(event.target.id);
// clickID
js.log(this.value);
// 123
}
</script>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| 이벤트 설정, bind 메소드 실행
1. 브라우저가 렌더링을 완료하면 window.onload 이벤트가 발생합니다.
2. window.onload에 설정된 핸들러 함수가 호출됩니다.
3. button#clickID에 이벤트를 설정하기 위해 엘리먼트 오브젝트를 생성합니다.
4. bind 메소드로 show 함수를 바인딩합니다.
5. 생성한 엘리먼트 오브젝트(element)에 이벤트 타입(onclick)과 핸들러 함수(show)를 설정합니다.
마우스로 버튼 클릭
6. 사용자가 버튼을 클릭합니다.
7. show 함수가 호출됩니다.
8. 첫 번째 파라미터에 bind 메소드의 두 번째 파라미터에 작성한 element가 설정됩니다.
9. 두 번째 파라미터에 이벤트 오브젝트가 설정됩니다.
10. show 함수에 작성한 자바스크립트 코드를 수행합니다.
|
27.15 bind()와 비동기 통신 바인딩#
- 클라이언트가 서버와 비동기 통신을 시작하면 다섯 번 통신 상태가 변경되며 변경될 때 마다 onreadystatechange 이벤트를 발생시킵니다. onreadystatechange에 콜백함수를 연결하여 처리해야합니다.
- bind 메소드로 this가 참조하는 오브젝트와 통신 오브젝트를 바인딩할 수 있으므로 콜백 함수에서 쉽게 처리할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| var sports = {
value: 123
};
function statusChange(xhr) {
if (xhr && xhr.readyState == 4) {
if (xhr.status > 199 && xhr.status < 300) {
debugger;
js.log(xhr.statusText);
js.log(this.value);
}
}
}
var xhr = new XHLHttpRequest();
xhr.open('get', 'https://httpbin.org/get', true);
xhr.onreadystatechange = statusChange.bind(sports, xhr);
xhr.send();
// OK
// 123
|
1
2
3
4
5
6
7
| 통신 준비 및 실행
1. 통신을 위한 통신 오브젝트를 생성합니다.
2. 통신 오브젝트(xhr)의 open 메소드로 서버와 통신을 시작합니다.
3. bind 메소드로 콜백함수를 바인딩합니다.
4. 통신 오브젝트에 콜백 함수를 설정합니다.
5. 통신 오브젝트(xhr)의 send 메소드로 데이터를 서버에 전송합니다.
비동기 통신으로 서버와 여러 건을 통신할 때 통신을 시작한 순서로 통신이 종료되지 않으므로 어떤 것이 종료되었는지 알 수 없습니다. bind 메소드로 this가 참조하는 오브젝트와 통신 오브젝트를 바인딩하면 통신 오브젝트단위로 서버에서 보낸 데이터를 this가 참조하는 오브젝트에서 처리할 수 있습니다.
|