17일차 - Javascript 문법 (4) 데이터 타입,호이스팅,This

이상민·2024년 8월 16일

TIL

목록 보기
16/50

1. 데이터 타입 심화

(1) 데이터 타입의 종류(기본형과 참조형)

(2) 메모리와 데이터에 관한 배경지식

1. 메모리와 데이터

  • 비트 : 컴퓨터가 이해할 수 있는 가장 작은 단위로 0과 1을 가지고 있는 메모리를 구성하기 위한 작은 조각
  • 바이트 : 0과 1만 표현하는 비트를 모두 찾기는 부담스러워 나온 새로운 단위로 1바이트는 8개의 비트로 구성되어 있다.

정적 타입 언어(C/C++,java)는 메모리의 낭비를 최소화하기 위해 데이터 타입별로 할당 메모리 영역을 정해놓았다. 숫자형 데이터를 저장할 경우 정해진 숫자만 허용하고 이상의 숫자를 입력하면 오류가 나거나 잘못된 값이 저장되므로 이를 대처하기 위해서는 사용자가 직접 변환해야하는(int) 번거로운 작업이 필요했다.

한편 메모리 용량이 과거보다 월등히 커진 상황에서 등장한 자바스크립트는 상대적으로 메모리 관리에 대한 압박에서 자유로워졌다. 때문에 메모리 공간을 좀 더 넉넉하게 할당했고 위와같은 번거로운 상황이 덜 발생하게 되었다.

(3) 변수 선언과 데이터 할당

  • 변수 선언, 할당
/** 선언과 할당을 풀어 쓴 방식 */
var str;
str = 'test!';

/** 선언과 할당을 붙여 쓴 방식 */
var str = 'test!';
  • 변수란 변경 가능한 데이터가 담길 수 있는 공간, 또는 그릇이다. 어떤 변수를 선언하면 컴퓨터는 메모리에서 a라는 변수명을 가진 주소를 검색해 해당 공간에 담긴 데이터를 반환할 것이다.

(4) 기본형 데이터와 참조형 데이터

  • 불변값과 불변성(with 기본형 데이터)
    변수와 상수를 구분하는 성질은 변경 가능성이다. 즉 한번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재 할당할 수 있는지의 여부가 관건, 반면 불변성 여부를 구분할 떄의 변경 가능성의 대상은 데이터 영역의 메모리이다.
// 'abc'라는 값이 데이터영역의 @5002라는 주소에 들어갔다고 가정하자
var a = 'abc';

// 'def'라는 값이 @5002라는 주소에 추가되는 것이 아님
// @5003에 별도로 'abcdef'라는 값이 생기고 a라는 변수는 @5002 -> @5003
// 즉, "변수 a는 불변하다." 라고 할 수 있다.
// 이 때, @5002는 더 이상 사용되지 않기 때문에 가비지컬렉터의 수거 대상이 된다.
a = a + 'def';
  • 가변값과 가변성(with 참조형 데이터)
    참조형 데이터의 변수 할당 과정
// 참조형 데이터는 별도 저장공간(obj1을 위한 별도 공간)이 필요합니다!
var obj1 = {
	a: 1,
	b: 'bbb,
};
  • 변수 복사의 비교
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형

var b = a; //기본형
var obj2 = obj1; //참조형

b = 15;
obj2.c = 20;

기본형과 참조형의 변수 복사 시 주요한 절차의 차이점

  • 기본형
    • 숫자 15라는 값을 데이터 영역에서 검색 후 없다면 생성
    • 검색한 결과주소 또는 생성한 주소를 변수 영역 b에 갈아끼움
    • a와 b는 서로 다른 데이터 영역의 주소를 바라보고 있기 때문에 영향 없음
  • 참조형
    • 숫자 20이라는 값을 데이터 영역에서 검색 후 없다면 생성
    • 검색한 결과주소 또는 생성한 주소 obj2에게 지정되어 있는 별도 영역(7103~)에 갈아끼움
    • obj1도 똑같은 주소를 바라보고 있기 때문에 아래와 같이 obj1까지 변경이 됨
// 기본형 변수 복사의 결과는 다른 값!
a !== b;

// 참조형 변수 복사의 결과는 같은 값!(원하지 않았던 결과)
obj1 === obj2;

(5) 불변 객체

  • 불변객체란?
    먼저 객체는 객체의 속성에 접근해 값을 변경하면 가변이 성립했다. 반면 객체 데이터 자체를 새로운 데이터를 할당하고자 하면 기존 데이터가 변경 되지 않았다. (불변)
  • 불변객체가 필요한 이유 (아래 그림을 통해 알아보자)
// user라는 객체를 생성
var user = {
	name: 'wonjang', // 최초에 이름은 wonjang 이다.
	gender: 'male',
};
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 특징 : 객체의 프로퍼티(속성)에 접근해서 이름을 변경 -> 가변
var changeName = function (user, newName) { // 이름을 변경하는 함수, 'changeName'을 정의
	var newUser = user; // 출력값 : 새로운 user 객체
	newUser.name = newName;
	return newUser;
};
var user2 = changeName(user, 'twojang');
// 아래 로직 수행 X
if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // twojang twojang
console.log(user === user2); // true

// user 객체를 생성
var user = {
	name: 'wonjang',
	gender: 'male',
};
// 이름을 변경하는 함수 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티에 접근하는 것이 아니라, 아에 새로운 객체를 반환 -> 불변
var changeName = function (user, newName) {
	return {
		name: newName,
		gender: user.gender,
	};
};
// 변경한 user정보를 user2 변수에 할당
// 불변이기 때문에 user1은 영향 X
var user2 = changeName(user, 'twojang');

// 아래 로직이 수행
if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // wonjang twojang
console.log(user === user2); // false 👍

더 나은 방법 ( 얕은 복사 ) ✔ vs ( 깊은 복사) ✔

  • 얕은 복사 패턴 예시
var copyObject = function (target) {
	var result = {};

	// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근가능
	// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경
	for (var prop in target) {
		result[prop] = target[prop];
	}
	return result;
}
//위 패턴을 우리 예제에 적용
var user = {
	name: 'wonjang',
	gender: 'male',
};

var user2 = copyObject(user);
user2.name = 'twojang';

if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name);
console.log(user === user2);
  • 얕은 복사의 한계점 : 중첩된 객체에 대해서는 완벽한 복사가 불가능..하고, 중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티를 복사할 때, 주소값만 복사..

  • 깊은 복사란?
    내부의 모든 값들을 하나하나 다 찾아서 모두 복사하는 방법

var user = {
	name: 'wonjang',
	urls: {
		portfolio: 'http://github.com/abc',
		blog: 'http://blog.com',
		facebook: 'http://facebook.com/abc',
	}
};

// 1차 copy
var user2 = copyObject(user);

// 2차 copy -> 이렇게까지 해줘야만 해요..!!
user2.urls = copyObject(user.urls);

user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio);

user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog);

결론은 깊은복사를 통한 재귀적 수행이 답이다 !

var copyObjectDeep = function(target) {
	var result = {};
	if (typeof target === 'object' && target !== null) {
		for (var prop in target) {
			result[prop] = copyObjectDeep(target[prop]);
		}
	} else {
		result = target;
	}
	return result;
}
//결과 확인
var obj = {
	a: 1,
	b: {
		c: null,
		d: [1, 2],
	}
};
var obj2 = copyObjectDeep(obj);

obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;

console.log(obj);
console.log(obj2);

2. 실행컨텍스트(스코프, 변수, 객체, 호이스팅 등등)

  • 실행컨텍스트란 ?
    자바스크립트의 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체를 뜻함
    실행컨텍스트를 이해하기 위해서는 먼저 "콜 스택"에 대한 이해가 반드시 필요!!

  • 콜 스택(call stack)이란 ?
    실행할 코드에 제공할 환경 정보들을 모아놓은 객체로 동일 환경에 있는 코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하는 스택의 한 종류이다.

// ---- 1번
var a = 1;
function outer() {
	function inner() {
		console.log(a); //undefined
		var a = 3;
	}
	inner(); // ---- 2번
	console.log(a);
}
outer(); // ---- 3번
console.log(a);

실행 컨텍스트 객체의 실체=( 담기는 정보 )

1. VariableEnvironment

a. 현재 컨텍스트 내의 식별자 정보(record)를 갖고있음

1) var a = 3

b. 외부 환경 정보(=outer)를 갖고있음

2. LexicalEnvironment

a. VariableEnvironment와 동일하지만, 변경사항을 실시간으로 반영

호이스팅(Hoisting)(끌어 올리기) o((>ω< ))o

  • 호이스팅은 함수 내의 변수 및 함수 선언을 각 유효 범위의 최상단으로 끌어 올려주는 JS의 특징이다. 실제로 코드가 끌어올려지는 것은 아니고, 자바스크립트 parser가 내부적으로 끌어올려서 처리하는 것.
    호이스팅 참고 블로그!

호이스팅 규칙

  1. 매개변수 및 변수는 선언부를 호이스팅 한다.
    예시1)
//action point 1 : 매개변수 다시 쓰기(JS 엔진은 똑같이 이해한다)
//action point 2 : 결과 예상하기
//action point 3 : hoisting 적용해본 후 결과를 다시 예상해보기

// <매개변수 적용 전>
function a (x) { // 매개변수 적용시 아래처럼 var x = 1; 로 넘어감
	console.log(x);
	var x;
	console.log(x);
	var x = 2;
	console.log(x);
}
a(1);
// <매개변수 적용 후>------------------------------------------------------------
function a () {
	var x = 1;
	console.log(x);
	var x;
	console.log(x);
	var x = 2;
	console.log(x); // 예상) 1 → undefined → 2
}
a(1);
// <호이스팅 적용 후>-----------------------------------------------------------
function a () {
	var x;
	var x;
	var x;

	x = 1;
	console.log(x);
	console.log(x);
	x = 2;
	console.log(x); // 1, 1, 2
}
a(1);

예시)2

//action point 1 : 결과 값 예상해보기
//action point 2 : hoisting 적용해본 후 결과를 다시 예상해보기

// <적용 전>
function a () {
	console.log(b);
	var b = 'bbb';
	console.log(b);
	function b() { }
	console.log(b); // 예상) 에러(또는 undefined), ‘bbb’, b함수
}
a();
// <호이스팅 적용>------------------------------------------------------------
function a () {
	var b; // 변수 선언부 호이스팅
	function b() { } // 함수 선언은 전체를 호이스팅

	console.log(b);
	b = 'bbb'; // 변수의 할당부는 원래 자리에

	console.log(b);
	console.log(b); // b함수, ‘bbb’, ‘bbb’
}
a();
// <함수선언문을 함수 표현식으로 변경>--------------------------------------------
function a () {
	var b; // 변수 선언부 호이스팅
	var b = function b() { } // **함수 선언은 전체를 호이스팅**

	console.log(b);
	b = 'bbb'; // 변수의 할당부는 원래 자리에

	console.log(b);
	console.log(b);
}
a();

함수 정의의 3가지 방식✔😜

// 함수 선언문. 함수명 a가 곧 변수명
// function 정의부만 존재, 할당 명령이 없는 경우
function a () { /* ... */ }
a(); // 실행 ok

// 함수 표현식. 정의한 function을 별도 변수에 할당하는 경우
// (1) 익명함수표현식 : 변수명 b가 곧 변수명(일반적 case에요)
var b = function () { /* ... */ }
b(); // 실행 ok

// (2) 기명 함수 표현식 : 변수명은 c, 함수명은 d
// d()는 c() 안에서 재귀적으로 호출될 때만 사용 가능하므로 사용성에 대한 의문
var c = function d () { /* ... */ } 
c(); // 실행 ok
d(); // 에러!

Remind 🎯

- 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.
- 그 객체 안에는 3가지가 존재한다.
   ✓ VariableEnvironment
   ✓ LexicalEnvironment
   ✓ ThisBindings
- VELE는 실행컨텍스트 생성 시점에 내용이 완전히 같고, 이후 스냅샷 유지 여부가 다르다.
- LE는 다음 2가지 정보를 가지고 있다.record(=environmentRecord) ← 이 record의 수집과정이 hoisting
   ✓ outer(=outerEnvironmentReference)

함수 선언문과 표현식의 실직적인 차이 예시🧔

console.log(sum(1, 2));
console.log(multiply(3, 4));

function sum (a, b) { // 함수 선언문 sum
	return a + b;
}

var multiply = function (a, b) { // 함수 표현식 multiply
	return a + b;
}
// 함수 선언문은 전체를 hoisting
function sum (a, b) { // 함수 선언문 sum
	return a + b;
}

// 변수는 선언부만 hoisting

var multiply; 

console.log(sum(1, 2));
console.log(multiply(3, 4));

multiply = function (a, b) { // 변수의 할당부는 원래 자리
	return a + b;
};

스코프 체인

  • 스코프 체인(Scope Chain)은 일종의 리스트로서 전역 객체와 중첩된 함수의 스코프의 레퍼런스를 차례로 저장하고, 의미 그대로 각각의 스코프가 어떻게 연결(chain)되고 있는지 보여주는 것
// 아래 코드를 여러분이 직접 call stack을 그려가며 scope 관점에서 변수에 접근해보세요!
var a = 1;
var outer = function() {
	var inner = function() {
		console.log(a); // undefined
		var a = 3;
	};
	inner();
	console.log(a); // outer 은 전역 영역 즉 1이 된다.
};
outer();
console.log(a); // 전역 영역 내부에서 해결한 1이 나옴

3. this(정의, 활용방법, 바인딩, call, apply, bind)

Remind 🎯

- 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.
- 그 객체 안에는 3가지가 존재한다.
   ✓ VariableEnvironment
   ✓ LexicalEnvironment
   ✓ ThisBindings

This 란?

  • this는 실행 컨텍스트가 생성될 때 결정된다. 즉 this를 bind한다(=묶는다) 라고 한다. 다시 말하면, this는 함수를 호출할 때 결정된다.
런타임 환경? 
여러분들이 javascript로 만들어놓은 프로그램이 구동중인 환경을 말하죠. 
우리는 node 파일이름.js로 vscode 상에서 구동하고 있으니 node 환경이라고 할 수 있구요.
html 파일 안에 숨겨놓아서 크롬브라우저 등에서 연다고 한다면 브라우저 환경이라고 할 수 있겠네요.   

1. 메서드로서 호출할 때 그 메서드 내부에서의 this

this의 할당

// CASE1 : 함수
// 호출 주체를 명시할 수 없기 때문에 this는 전역 객체를 의미
var func = function (x) {
	console.log(this, x);
};
func(1); // Window { ... } 1

// CASE2 : 메서드
// 호출 주체를 명시할 수 있기 때문에 this는 해당 객체(obj)를 의미
// obj는 곧 { method: f }를 의미하죠?
var obj = {
	method: func,
};
obj.method(2); // { method: ƒ } 2

함수로서의 호출과 메서드로서의 호출 구분 기준 : . []

  • .이든 []든 어떤 것으로 호출해도 결과는 같다.
var obj = {
	method: function (x) { console.log(this, x) }
};
obj.method(1); // { method: f } 1
obj['method'](2); // { method: f } 2

메서드 내부에서의 this

  • 위의 내용에서 보았듯이, this에는 호출을 누가 했는지에 대한 정보가 담긴다.
var obj = {
	methodA: function () { console.log(this) },
	inner: {
		methodB: function() { console.log(this) },
	}
};

obj.methodA();             // this === obj
obj['methodA']();          // this === obj

obj.inner.methodB();       // this === obj.inner
obj.inner['methodB']();    // this === obj.inner
obj['inner'].methodB();    // this === obj.inner
obj['inner']['methodB'](); // this === obj.inner

2. 함수로서 호출할 때 그 함수 내부에서의 this

  • 함수로서 '독립적으로' 호출할 때 this는 항상 전역객체를 가리킨다는 것!

메서드 내부함수에서의 this

  • 메서드의 내부라고 해도, 함수로서 호출한다면 this는 예외없이 전역 객체를 의미!
var obj1 = {
	outer: function() {
		console.log(this); // obj1
		var innerFunc = function() {
			console.log(this); // 전역객체, obj2
		}
		innerFunc();

		var obj2 = {
			innerMethod: innerFunc
		};
		obj2.innerMethod();
	}
};
obj1.outer();

메서드의 내부 함수에서의 this 우회

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

		// AS-IS
		var innerFunc1 = function() {
			console.log(this); // (2) 전역객체
		}
		innerFunc1();

		// TO-BE
		var self = this;
		var innerFunc2 = function() {
			console.log(self); // (3) { outer: ƒ }
		};
		innerFunc2();
	}
};

// 메서드 호출 부분
obj1.outer();

화살표 함수(=this를 바인딩하지 않는 함수)

  • ES6에서는 함수 내부에서 this가 전역객체를 바라보는 문제 때문에 화살표함수를 도입

    일반 함수와 화살표 함수의 가장 큰 차이점은 무엇일까?
    정답은 바로 this binding 여부가 가장 적절한 답😉

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

obj.outer();

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

  • 콜백함수 : 어떠한 함수, 메서드의 인자(매개변수)로 넘겨주는 함수
// 별도 지정 없음 : 전역객체
setTimeout(function () { console.log(this) }, 300);

// 별도 지정 없음 : 전역객체
[1, 2, 3, 4, 5].forEach(function(x) {
	console.log(this, x);
});

// 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);
});

4. 생성자 함수 내부에서의 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

명시적 this 바인딩

  • 자동으로 부여되는 상황별 this의 규칙을 깨고 this에 별도의 값을 저장하는 방법으로 크게 call / apply / bind 로 나눠진다.

1. Call 메서드

  • 호출 주체인 함수를 즉시 실행하는 명령어
var func = function (a, b, c) {
	console.log(this, a, b, c);
};

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

// 명시적 binding
// func 안에 this에는 {x: 1}이 binding돼요
func.call({ x: 1 }, 4, 5, 6}; // { x: 1 } 4 5 6

2. apply 메서드

  • call 메서드와 동일 but, 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

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

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

3. call / apply 메서드 활용

  • 물론 his binding을 위해 call, apply method를 사용하기도 하지만 더 유용한 측면도 있다.

1. 유사배열객체(array-like-object)에 배열 메서드를 적용

 - 유새 배열의 조건에는 먼저 반드시 length가 필요하며, 이것이 없으면 유사배열 인식x
 - index번호가 0번부터 시작해서 1씩증가해야한다 ! 안그러면 예상치 못한 결과 초래가능!

Remind (Slice() 함수) 🎯

- 슬라이스slice() 함수는 배열로부터 특정 범위를 복사한 값들을 담고 있는 새로운 배열을 만드는데 사용한다.
첫번째 인자로 시작 인덱스(index), 두번쨰 인자로 종료 인덱스를 받으며, 시작 인덱스부터 종료 인덱스까지 값을
복사하여 반환한다. 
//객체에는 배열 메서드를 직접 적용할 수 없어요.
//유사배열객체에는 call 또는 apply 메서드를 이용해 배열 메서드를 차용할 수 있어요.
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' ]

2. Array.from 메서드(ES6)

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

// 객체 -> 배열
var arr = Array.from(obj);

// 찍어보면 배열이 출력됩니다.
console.log(arr);

3. 생성자 내부에서 다른 생성자를 호출(공통된 내용의 반복 제거)

// student, Employee 모두 person 이다. name 과 gender 속성 모두 필요
// 따라서 student 와 Employee 인스턴스를 만들때 마다 세 가지 속성을 모두 각 생성자 함수에 넣기 보다는
// person 이라는 생성자 함수를 별도로 뺴는게 '구조화'에 좀 더 도움 !
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', '삼성');

4. 여러 인수를 묶어 하나의 배열로 전달할 때 apply 사용 가능

  • apply 미적용 예시
//비효율 적임
var numbers = [10, 20, 3, 16, 45];
var max = min = numbers[0];
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("apply => ", max, min); // apply => 45, 3

// 펼치기 연산자(Spread Operation)를 통하면 더 간편하게 해결도 가능 (장벽을 뚫어버림)
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max min); // 45, 3

4. bind 메서드

  • call과 비슷 but, 즉시 call 과는 다르게 즉시 호출하지는 않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 반환하는 메서드이다.
  • 예시
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

name 프로퍼티

  • 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);

// func와 bindFunc의 name 프로퍼티의 차이를 살펴보세요!
console.log(func.name); // func
console.log(bindFunc.name); // bound func

5. 화살표 함수의 예외사항

  • 화살표 함수는 실행 컨텍스트 생성 시, this를 바인딩하는 과정이 제외
var obj = {
	outer: function () {
		console.log(this);
		var innerFunc = () => {
			console.log(this);
		};
		innerFunc();
	};
};
obj.outer();

0개의 댓글