문제 설명 :
문자열로 구성된 리스트 strings와, 정수 n이 주어졌을 때, 각 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬하려 합니다. 예를 들어 strings가 ["sun", "bed", "car"]이고 n이 1이면 각 단어의 인덱스 1의 문자 "u", "e", "a"로 strings를 정렬합니다.
조건 :
strings는 길이 1 이상, 50이하인 배열입니다.
strings의 원소는 소문자 알파벳으로 이루어져 있습니다.
strings의 원소는 길이 1 이상, 100이하인 문자열입니다.
모든 strings의 원소의 길이는 n보다 큽니다.
인덱스 1의 문자가 같은 문자열이 여럿 일 경우, 사전순으로 앞선 문자열이 앞쪽에 위치합니다.
👩🏻 : 나는 처음 코드를 작성할 때 문제 설명만 듣고 조건을 모르는 상태에서 작성했기 때문에 마지막 조건에 부합하지 못하게 코드를 작성하였다..! 그리고 문제를 딱 마주했을 때 나는 오름차순을 해주는 메소드가 뭔지도 모르고 있는 상황이여서 구글링을 엄청나게 해서 어떻게든 해결을 했었다. 하지만 어쩐지 아주 간결하게 해결되었다고 생각했는데..ㅎ 일단 아래는 처음에 작성한 코드이다!
let strings = ["lee", "han", "byeol"];
let n = 1;
let solution = (strings, n) => {
console.log(strings.sort((a, b) => (a[n] >= b[n] ? 1 : -1)));
};
👩🏻 : 그리고 위에 말한 조건이 있다는 사실을 알게 되면서 안타깝지만 이미 답안을 다 봐버렸다..
그렇지만 어차피 몰랐을 것 같은 코드.. 열심히 해석하고 흡수하기로 했다. 🤸♀️ 왜냐면 처음에 내가 작성한 코드를 짤 때에도 나는 내가 예시 속 배열의 문자들에서 n의 값을 2로 잡는다면 e로 동일한데 그럼 어떡하지? 라고 생각은 했었는데 이와 관련된 부분이 조건에 있는 줄 모르기도 했고 방법도 생각이 안나서 고민하다가 그냥 넘겨버렸다.. 부족한 내 자신.. 아무튼 답을 확인하면 이렇다. ↓
function solution(strings, n) {
let result = [];
// 문자열 가장앞 글자 붙인 문자 배열 만들기
for (let i = 0; i < strings.length; i++) {
strings[i] = strings[i][n] + strings[i];
}
// 문자열 사전순 정렬
strings.sort();
// 앞글자 제거 후 리턴
for(let j = 0; j < strings.length; j ++) {
strings[j] = strings[j].replace(strings[j][0],"");
result.push(strings[j]);
}
return result;
}
👩🏻 : 항상 느끼지만 답을 보고나면 '와..저런 방법이..' 라는 생각에 충격을 받는다.. 왜 나는 저 방법을 생각하지 못할까..ㅎ 하면서 더 열심히 공부하고 문제를 마주치다 보면 꼭 실력이 늘거라고 믿어본다.. 답안처럼 n에 해당하는 index번째의 문자를 앞으로 꺼내서 정렬을 하는 방법은 상상도 못했다.. 물론 문제 풀이 팁에 따로 적혀 있었지만 못 본 것도 내 잘못이다! 앞으로 강의 자료에서 숙제 관련 부분 꼼꼼히 읽어보고 숙제 하면 되지 뭐! 지금은 배우는 단계이니깐ㅎㅎ
[1] 데이터타입의 종류
· 기본형 (Primitive type) : Number, String, Boolean, null, undefined, Symbol(ES6)
· 참조형 (Reference type) : Object 하위요소 → Array, Function, Date, RegExp, Map, WeakMap, Set, WeakSet / 참조형은 기본적으로 객체이다.
기본형과 참조형을 나누는 기준
(1) 값의 저장 방식 : 값이 메모리에 어떻게 저장되는지, 어떻게 복제되는지
기본형 : 값이 담긴 주소값을 바로 복제
참조형 : 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값 복제
(2) 불변성 여부 - 메모리 관점
기본형 : 불변성을 띈다.
참조형 : 불변성을 띄지 않는다.
[2] 메모리와 데이터에 관한 배경지식
· 비트 : 컴퓨터가 이해하는 가장 작은 단위 0,1 / 메모리를 구성하기 위한 작은 조각
· 바이트 : 8bit = 1byte / byte 단위로 메모리에 고유한 주소값 부여
· 메모리 : 모든 데이터는 byte 단위의 식별자인 메모리 주소값을 통해 서로 구분된다.
= byte는 메모리 주소값을 가지고 있어서 서로 구분되는 것이다.
[3] 변수 선언과 데이터 할당
(강의 자료에 나온 표 참고)
변수를 선언하고 데이터를 할당할 경우
변수 영역과 데이터 영역이 나누어져 있을 때 변수영역에 이름을 저장하고 데이터 영역에 데이터 값을 따로 저장한다. 그리고 변수 영역에서는 데이터 값이 저장된 주소 값만을 저장해놓고 데이터 값을 가져온다.
이 때, 값을 변수 영역에 바로 대입하지 않는 이유
1. 자유로운 데이터 변환
javascirpt에서 숫자는 항상 8byte 이지만, 문자는 고정이 아니다. (영문 1byte, 한글 2byte)
예를 들어 변수 영역에 문자 데이터가 직접적으로 할당되었다가 값이 변하여 늘어난다면 변수 영역에서 할당된 공간이 더 늘어나야 해서 모든 변수의 주소가 밀리게 된다.
2. 메모리의 효율적 관리
똑같은 데이터를 여러번 저장하게 되면 데이터 영역에는 중복되는 값을 한 개만 저장하고 변수 영역에서 그 데이터 값이 들어있는 데이터 영역의 주소값만 중복으로 참조해주면 된다.
데이터 값이 1자리 숫자라고 가정해보면 변수 영역에 변수이름과 숫자를 전부 적어줄 때마다 숫자의 크기인 8byte가 필요한데 / 변수 영역에서 중복되는 숫자의 주소값만 참조하면 굳이 8byte의 메모리가 필요하지 않다.
변수 영역에는 결국 변수의 이름과 참조되는 숫자의 데이터영역 주소값만 들어가면 되기 때문이다.
[4] 기본형 데이터와 참조형 데이터
1. 메모리 기준으로 다시 생각해보는 주요 개념
1-1. 변수 vs 상수
변수 : 변수 영역 메모리 변경 가능
상수 : 변수 영역 메모리 변경 불가능
1-2. 불변하다 vs 불변하지 않다.
불변하다 : 데이터 영역 메모리 변경 불가능
불변하지 않다. : 데이터 영역 메모리 변경 가능
2. 불변값과 불변성 with 기본형 데이터
예시)
var a='abc' 라고 하면 a라는 변수명은 변수 영역에, abc라는 값은 데이터 영역에 들어있는데
abc를 abcdef로 변경하고자 할 때 우리는 abc의 주소값에 있는 데이터 자체를 변경하는 것이 아니라 abcdef를 새로운 주소에 값으로 할당해서 a가 있는 변수영역에서 참조하는 데이터 영역의 주소 값을 abcdef가 있는 데이터 영역으로 변경해준다. 이 때, 우리가 데이터 영역의 abc를 바꾸는 것이 아니라 새로 만들어서 참조하는 것이기 때문에 '불변하다' 라고 하는 것이고 변수 영역에서는 데이터 영역의 주소 값을 갈아끼울 수 있기 때문에 변수라고 한다.
더 이상 사용되지 않는 데이터 영역의 값(예를 들어 abc)은 JavaScript에 가비지 컬렉터가 수거한다. → 메모리 관리
[5] 불변 객체(얕은 복사와 깊은 복사)
강의의 예시 및 강의자료를 보는 것이 좋음!
* 가변하다라는 위험성을 불변한 것처럼 바꿔주려는 노력이 필요하다!
· 얕은 복사 : 바로 아래 단계의 값만 복사
· 얕은 복사 문제점 : 중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티를 복사할 때, 주소값만 복사
얕은 복사에서는 중첩된 객체에서 1depth 까지만 접근하기 때문에 객체 속 객체의 속성은 접근 불가
· 깊은 복사 : 내부의 모든 값들을 하나하다 다 찾아서 모두 복사
결론 : 객체의 프로퍼티 중, 기본형 데이터는 그대로 복사 + 참조형 데이터는 다시 그 내부의 프로퍼티를 복사
→ 재귀적 수행! : (다시 돌아간다) 함수나 알고리즘이 자기 자신을 호출하여 반복적으로 실행되는 것
[6] undefined와 null
= 없음을 의미하는 값이지만 차이가 있고 목적 또한 다르다.
1. undefined
개발자가 직접 지정 가능하지만 그런 경우는 거의 없다.
일반적으로 자바스크립트 엔진에서 값이 있어야 할 것 같은데 없는 경우 자동으로 부여
case 3개 ↓
1-1. 변수에 값이 지정되지 않은 경우. 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
1-2. .이나 [ ]로 접근하려 할 때, 해당 데이터가 존재하지 않는 경우
1-3. return문이 없거나 호출되지 않는 함수의 실행 결과
⭐ '없다'를 명시적으로 표현하고 싶을 때는 undefined 사용XXXXX
# 실행컨텍스트 개념 : 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
# 실행컨텍스트 역할 : 호이스팅, 외부 환경 정보 구성, this값 설정
Stack : Last in, first out (LIFO)
Queue : First in, first out (FIFO)
# 콜 스택
Stack의 방식을 따른다.
동일한 환경에 있는 코드 실행 시 필요한 환경 정보를 모아 컨텍스트(객체) 구성 후 이것을 stack의 한 종류인 콜스택에 쌓아올린다.
# 컨텍스트의 구성 : 전역공간, eval()함수, 함수(우리가 흔히 실행컨텍스트를 구성하는 방법)
* 실행 컨텍스트가 실행되는 시점은 콜 스택의 맨 위에 쌓이는 순간을 의미
* 즉, 맨 위에 있는 순간이 현재 실행 컨텍스트가 관여하게 되는 시점이다.
# 실행컨텍스트 객체의 안에 담기는 정보, 실체
1. VariableEnvironment (VE)
2. LexicalEnvironment (LE)
1번, 2번 한 번에 설명
· 현재 컨텍스트 내의 식별자 정보(=record)를 가지고 있다.
예를 들어 var a=3; 일때 var a 를 의미한다.
· 외부 환경 정보를 가지고 있다. // 후에 다시 설명
* 1번과 2번은 최초에 생길 때는 완전히 같지만 변경사항을 유지하는지의 여부만 다르다!
LE는 시간이 갈수록 변경사항을 계속 반영하며 업데이트 된다. = snapshot 유지X
VE는 생겼을 때의 모습을 계속 간직하며 유지된다. = snapshot 유지
⭐ 결국, 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담은 다음,
이를 그대로 복사해서 LE를 만들고 이후에는 주로 LE를 활용한다.
VE랑 LE가 가지고있는 record와 outer 하나씩 설명 ↓
# record 와 호이스팅 (record의 수집 과정이 hoisting)
· record - 현재 컨텍스트와 관련된 코드의 식별자 정보들 저장(수집)
· 수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자
· 수집 방법 : 컨텍스트 내부를 처음부터 끝까지 순서대로 훑으며 수집한다. (실행하는건 아님!)
· 호이스팅 - 변수 정보 수집 과정을 이해하기 쉽게 설명한 가상 개념
· 호이스팅의 개념은 record 즉, 식별자 정보를 수집하는 것에서 나온다.
· 호이스팅 규칙
1. 매개변수 및 변수는 선언부를 호이스팅 한다. = 식별자 정보를 위로 끌어올린다.
2. 함수 선언은 전체를 호이스팅 한다.
함수라고 해서 무조건 다 호이스팅 되는 것은 아니다.
함수에는 함수 선언문도 있고, 함수 표현식도 있다.
함수 정의의 3가지 방식
a. 함수 선언문 - 함수 정의부만 있다. 할당 명령이 없다.
function a ( ) { }
b. 함수 표현식 - 정의한 fucntion을 별도 변수에 할당
(1) 익명함수표현식 : 변수명 b가 곧 변수명
var b = function ( ) { }
(2) 기명함수표현식 : 변수명은 c, 함수명은 d / 활용성이 거의 없다.
d는 c안에서 재귀적으로 호출될 때만 사용 가능 , 사용성에 대한 의문
var c = function d( ) { }
c( ); // 실행ok
d( ); // 에러
# 함수 선언문과 함수 표현식은 호이스팅 면에서 다르다!
· 함수 선언문은 함수 전체가 위로 끌어올려 진다.
· 함수 표현식은 변수 부분만 위로 끌어올려 진다.
→ 함수 선언문 보다는 함수 표현식을 사용하는 습관을 들여야한다!
# outer (outerEnvironmentReference) 환경 참조정보
· outer의 역할: 스코프 체인이 가능토록 하는 것(외부 환경의 참조정보)라고 할 수 있다.
주요 용어
1. 스코프
식별자에 대한 유효범위를 의미, = 변수가 어디까지 영향을 미칠 수 있느냐.
대부분 언어에 존재, 당연히 js에도 존재
2. 스코프 체인
식별자의 유효범위를 안에서부터 밖으로 차례로 검색해나가는 것
outer는 현재 호출된 함수가 선언될 당시의 외부환경정보 LexicalEnvironment를 가지고 있다.
가지고 있는 이유 : 그 때의 변수 정보 등을 참조하기 위해서 → 스코프 체이닝이 가능하게 한다.
⭐ 실행컨텍스트 과정 최종 정리 : 각각의 실행 컨텍스트는 LE안에 record와 outer를 가지고 있고, outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE 정보가 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있다.
this
다른객체지향언어 - 클래스로 생성한 인스턴스
JavaScript - 어디에서나 사용될 수 있고 상황별로 다른 의미를 가질 수 있다.
[1] 상황에 따라 달라지는 this
· this는 실행 컨텍스트가 생성될 때 결정된다. = bind된다(묶는다) → this는 함수를 호출할 때 결정된다.
a. 전역 공간에서의 this
전역환경에 대해 이야기 할 때는 runtime을 고려해야 한다.
run+time → 코드가 돌아가는 환경
1. 노드(전역환경) : this === global 객체
2. 브라우저 : this === window 객체
b. 메서드로서 호출할 때 그 메서드 내부에서의 this
1. 함수 vs 메서드
함수와 메서드는 비슷해 보이지만 독립성의 차이가 있다.
이것은 this를 결정하는데 중요한 역할을 한다.
· 함수 : 자체로 수행될 수 있다. / 함수명();
함수의 this → 전역객체 = 호출의 객체를 명시할 수 없기 때문에
· 메서드 : 종속적인 것이기 때문에 자신을 호출한 대상 객체에 대한 동작을 수행한다. / 객체.메서드명();
메서드의 this → 호출의 주체
· 함수로서의 호출과 메서드로서의 호출 구분 기준 : 점(.) 과 대괄호([ ]) 이다.
# 함수로서의 호출을 할 때 그 함수 내부에서의 this
· 어떤 함수를 함수로서 호출하면 this가 지정되지 않는다 / 호출 주체를 알 수 없기 때문
· 실행 컨텍스트 활성화 당시 this가 지정되지 않은 경우이다. this는 전역 객체를 의미.
· 함수로서 독립적으로 호출하면 this는 항상 전역객체를 가리킨다는 것을 주의해야 한다.
# 메서드의 내부 함수에서의 this
· ⭐ 메서드의 내부라고 하여도, 함수로서 호출된다면 this는 전역 객체를 의미함!
# 메서드 내부 함수에서의 this 우회
상단에서 본 내용이 this에 대해서 개발자 입장에서는 이해가 잘 안되기 때문에 이를 우회할 수 있는 방법들을 찾게 되었다.
✍🏻 개발자로 일을 시작하면 AS-IS, TO-BE라는 말을 많이 듣게 된다!
# 콜백 함수 호출 시 그 함수 내부에서의 this
→ 함수를 호출할 때 this를 잃어버리는 현상과 굉장히 맞닿아 있다.
⭐ 콜백 함수도 함수다!
· 콜백함수는 기본적으로 전역 객체를 무조건 바라보게 되어있다고 생각하면 된다.
· 단, 콜백 함수를 넘겨받은 함수에서 콜백 함수에 별도로 this를 지정한 경우 예외적으로 그 대상을 참조한다.
아래의 예시들도 콜백 함수이지만 함수이고 함수로서의 호출이기 때문에 this를 다 잃어버리게 되고
thisbinding을 하면 다 전역 객체를 바라본다.
(1) 별도 지정 없음 : 전역객체
setTimeout(function () { console.log(this) }, 300);
(2) 별도 지정 없음 : 전역객체
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this, x);
});
(3) addListener 안에서의 this는 항상 호출한 주체의 element를 return 하도록 설계되었다.
예시에서 this는 button을 의미한다.
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function(e) {
console.log(this, e);
});
✍🏻 → 예외 : addListener는 기본적으로 자신이 콜백 함수를 호출할 때 자신이 this를 상속하게끔 되어있다.
addListener를 만든 사람이 지정해놓은 규칙같은 것!
# 생성자 함수 내부에서의 this
· 생성자 : 구체적인 인스턴스를 만들기 위한 일종의 틀
· 새로운 인스턴스를 만들 때 마다 this는 달라진다.
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7); //this : choco
var nabi = new Cat('나비', 5); //this : nabi
[2] 명시적 this 바인딩
# 자동으로 this가 bind 되는 규칙을 깨고 명시적으로 지정하는 방법이 있다.
call, apply, bind
var func = function (a, b, c) {
console.log(this, a, b, c);
};
// no binding
// 출력값 : Window{ ... } 1 2 3
// 출력되는 this에 전역 객체인 Window나 Global이 담긴다.
func(1, 2, 3);
// 명시적 binding
// 출력값 : { x: 1 } 4 5 6
// func 안에 this에는 {x: 1}이 binding 된다.
func.call({ x: 1 }, 4, 5, 6}; // { x: 1 } 4 5 6
· 호출 주체인 함수를 즉시 실행하는 명령어
· call을 사용하여, 첫 번째 매개변수에 this로 binding할 객체를 넣어주면 명시적으로 binding할 수 있다.
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
// 출력값 : 4 5 6
obj.method.apply({ a: 4 }, [5, 6]);
· call 메서드와 완전히 동일하다.
· 다만, this에 binding할 객체는 똑같이 넣어주고 나머지 부분은 배열 형태로 넘겨준다. ← [ ] 대괄호 사용
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
객체에는 배열 메서드를 직접 적용할 수 없기 때문에 현재 예시에서는 call 또는 apply 메서드를 이용해 배열 메서드를 차용할 수 있다. ↓
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' ]
call, apply 함수는 즉시 실행 함수이기 때문에 즉시 실행하면서 this binding을 하는 그 this자리에 해당 유사 배열 객체를 넣어줌으로써 이 기능을 수행하게끔 한다.
하지만 예제 코드에서의 사용은 call, apply메서드의 원래의 목적을 벗어나게 사용하는 것이다.
그래서 나온 것 ↓
(2) Array.from 메서드 (ES6)
객체를 배열로 아주 쉽게 바꿔주는 메서드이다.
· 유사배열객체 형태 ↓
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
객체를 배열로 바꿔주려면
var arr = Array.from(obj);
확인해보면
console.log(arr);
출력값 : ['a', 'b', 'c'] ← 배열 형태로 출력된다.
(3) 생성자 내부에서 다른 생성자를 호출 (공통된 내용의 반복 제거)
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
function Student(name, gender, school) {
Person.call(this, name, gender); // 여기서 this는 student 인스턴스!
// this.name = name; // 생략된다!!!!!!!!!!!!!!!!!!!!
// this.gender = gender; // 생략된다!!!!!!!!!!!!!!!!!!!!
this.school = school;
}
function Employee(name, gender, company) {
Person.apply(this, [name, gender]); // 여기서 this는 employee 인스턴스!
// this.name = name; // 생략된다!!!!!!!!!!!!!!!!!!!!
// this.gender = gender; // 생략된다!!!!!!!!!!!!!!!!!!!!
this.company = company;
}
var kd = new Student('길동', 'male', '서울대');
var ks = new Employee('길순', 'female', '삼성');
설명 : 기존 Student()와 Employee()에서 중복되는 name과 gender라는 값을 가지는 Person이라는 생성자 함수를 만들어서 각 함수 호출 시 인자로 받아오는 name과 gender를 매개변수로 넣어놔준다.
그리고 각 함수에 Person을 즉시 실행 함수인 call로 넣어주게 되면 Person을 즉시 실행 해주면서 this binding을 각 함수에서의 this(Student, Employee)가 들어가진다.
그러면서 Person.call(this, name, gender)의 형식으로 넣어주게 되면 호출 시 넣어주는 인자 값이 들어가지면서 새로운 인스턴스를 즉시 생성해준다.
이렇게 되면 기존에 있던 중복되는 코드들이 사라지게 되면서 코드의 효율성이 좋아진다
(4) 여러 인수를 묶어 하나의 배열로 전달할 때 apply 사용할 수 있다.
· apply 메소드 사용 전 ↓
//비효율
var numbers = [10, 20, 3, 16, 45];
var max = min = numbers[0]; // max값과 min 값을 최초의 numbers의 0번째로 지정 = 10
numbers.forEach(function(number) {
// 현재 돌아가는 숫자가 max값 보다 큰 경우
if (number > max) {
// max 값을 교체
max = number;
}
// 현재 돌아가는 숫자가 min값 보다 작은 경우
if (number < min) {
// min 값을 교체
min = number;
}
});
console.log(max, min);
· apply 메소드 사용 후 ↓
//효율
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);
apply 메소드를 사용함으로써 바로 실행하게 해준다. 이 때 this 값은 상관없기 때문에 null을 넣어준 것이고 numbers 라는 배열을 넣어줌으로써 Math.max 메소드의 기능으로 인해서 바로 max나 min 값을 구해진다.
· spread operator(펼치기 연산자) 사용 후 ↓
// 펼치기 연산자(Spread Operation)를 통하면 더 간편하게 해결도 가능해요
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max min);
더욱 간편하게 해결 가능하다.
Math.max()는 Math.max(...array) 형태로 작성하여 배열을 펼칠 수 있는데 펼치는게 중요한 이유는
원래 Math.max()는 콤마(,)형태로 구분된 숫자들의 나열로서 표현되야 하기 때문이다.
현재 예시에서는 numbers를 배열의 형태로 가지고 있기 때문에 풀어주는 작업이 필요하다.
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(5, 6, 7, 8); // { x: 1 } 5 6 7 8
// 부분 적용 함수 구현
var bindFunc2 = func.bind({ x: 1 }, 4, 5); // 4와 5를 미리 적용
bindFunc2(6, 7); // { x: 1 } 4 5 6 7
bindFunc2(8, 9); // { x: 1 } 4 5 8 9
(3) name 프로퍼티!
bind 메서드를 적용해서 새로 만든 함수는 name 프로퍼티를 가지고 있고
name 프로퍼티에는 ‘bound’ 라는 접두어가 붙기 때문에 추적하기가 쉽다.
bound → bind의 수동태 / = bind가 되었다.
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
var bindFunc = func.bind({ x:1 }, 4, 5);
// func와 bindFunc의 name 프로퍼티의 차이를 살펴보세요!
console.log(func.name); // func
console.log(bindFunc.name); // bound func
(4) 상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기
4-1. 내부함수
· 메서드의 내부함수에서 메서드의 this를 그대로 사용하기 위한 방법
· 변수를 활용한 우회법보다 call, apply, bind를 사용하면 깔끔하게 처리가 가능하다.
call 메서드 사용 예시 ↓
var obj = {
outer: function() {
console.log(this); // obj
var innerFunc = function () {
console.log(this);
};
// call을 이용해서 즉시실행하면서 this를 넘겨주었습니다
innerFunc.call(this); // obj
}
};
obj.outer();
bind 메서드 사용 예시 ↓
var obj = {
outer: function() {
console.log(this);
var innerFunc = function () {
console.log(this);
}.bind(this); // innerFunc에 this를 결합한 새로운 함수를 할당
innerFunc();
}
};
obj.outer();
· call 메서드는 즉시 실행 함수이기 때문에 bind 메서드 처럼 이후에도 어떤 식으로든 사용할 수 있게 this를 붙여두고 나중에 사용하는 목적을 가지는 bind 메서드를 더 많이 사용한다.
(5) 화살표 함수의 예외사항
# 화살표 함수는 this를 binding하는 과정이 없다. → this가 전역 객체로서 새롭게 세팅되는 케이스가 없다.
# 화살표 함수안에서의 this는 절대로 전역 객체로 세팅되지 않는다. 아무리 함수로서 호출이 되더라도!
결론 : 스스로 맞는 방법으로 써라~! 무슨 방법을 쓰는지 보다는 해당 방법을 알고 있냐는 것이 더 중요하다!