티스토리 뷰

 

▶함수

자바스크립트에서 함수는 가장 중요한 개념 중 하나이며 자바스크립트 함수만의 독특한 특징들이 있습니다.

함수의 특징을 얼마나 잘 이해하느냐가 자바스크립트 개발자로서의 역량을 판가름하는 기준이 될 수 있겠습니다.

단순한 함수 정의나 호출을 통해 결과 값을 얻는 것 이외에 this 바인딩, 클로저 등 자바스크립트 함수만의 특징을 제대로 이해하고 있어야 합니다.

 

1) 함수란 무엇인가?

함수는 객체의 특별한 형태이며 문(statement)으로 구성된 몸체를 가진 하나의 실행 단위입니다.

function doSomething() {
	console.log('hello javascript');
}

또한 자바스크립트 함수는 일급 함수(first-class function)로서 다른 함수의 매개변수나 반환 값으로도 사용할 수 있습니다.

function finishSomething(callback) {
	callback();
   	console.log('finish');
}
finishSomething(doSomething);

doSomething() 함수를 finishSomething() 함수의 인자로 넘긴 것을 볼 수 있습니다.

다른 함수의 인자로 넘어가는 함수를 콜백 함수라고 부르며, 이 패턴은 자바스크립트에서 아주 많이 쓰입니다.

 

가장 대표적인 예로는 DOM에 이벤트를 추가하는 addEventListener() 함수가 있습니다.

button.addEventListener('click', callback);

 

[NOTE]

일급 함수는 아래와 같은 조건을 만족해야 합니다. 자바스크립트의 함순느 이 조건을 모두 만족하기 때문에 일급 함수라고 할 수 있습니다.

- 변수에 함수를 할당할 수 있습니다.

- 함수를 인자로 전달할 수 있습니다.

- 함수를 반환 값으로 사용할 수 있습니다.

 

2) 함수의 정의 방법

자바스크립트의 함수는 function 키워드로 정의되며 다음과 같은 구성 요소를 가지고 있습니다.

 

① 함수의 이름(식별자) : 함수를 할당할 변수의 이름입니다.

② 함수의 매개변수 : 매개변수는 괄호 안에서 쉼표로 분리하며, 함수의 몸체에서 지역 변수처럼 사용됩니다.

③ 함수의 몸체 : 중괄호({}) 안에 정의하며, 함수가 호출될 때마다 실행되는 문의 집합입니다.

함수의 구성 요소

함수를 생성하는 방법은 세 가지가 있습니다.

함수 선언문, 함수 표현식 그리고 Function 생성자 함수를 사용하는 방법입니다.

참고로, Function 생성자 함수는 보안 및 성능 문제가 있어 권장되지 않습니다.

▷함수 선언문

함수 선언문은 함수의 이름, 매개변수, 몸체로 구성되며, 함수의 이름이 반드시 정의되어야 합니다.

함수 선언문이 실행되면 함수의 이름과 동일한 변수를 정의하여 함수 객체를 변수에 할당합니다.

function multiply(a, b) {
	return a * b;
}

함수 선언문으로 multiply() 함수를 정의하였습니다.

정확히 말하면 함수의 이름과 동일한 multiply라는 변수를 선언하여 함수 객체를 할당하는 것입니다.

 

함수 선언문에는 독특한 특징이 있습니다.

흔히 말하는 호이스팅(Hoisting)으로 인해 함수가 선언된 위치에서 코드의 최상단으로 끌어올려집니다.

따라서 이 함수는 선언된 위치보다 상단에서 호출될 수 있습니다.

console.log(multiply(2, 3)); // 6

funtion multiply(a, b) {
 	return a * b;
}

예제 코드처럼 함수 선언문으로 정의한 함수(multiply())는 호이스팅되기 때문에 정의된 위치보다 앞서 호출될 수 있습니다.

호이스팅은 나중에 더 자세히 다룰 예정입니다.

 

▷함수 표현식

함수 표현식은 함수 선언문과 달리 함수의 이름이 선택 사항이며, 변수에 함수를 직접 할당합니다.

const multiply = function (a, b) {
	return a * b;
}

함수 선언식의 예제를 함수 표현식으로 변경한 예제 코드입니다.

함수 선언문과 달리 함수의 이름을 생략하였고, multiply라는 변수를 선언하여 함수 객체를 할당하였습니다.

여기서 multiply가 함수의 이름이 아니라 변수라는 것을 명심해야 합니다.

이렇게 이름이 없는 함수를 익명 함수(anonymous function) 표현식이라고 부릅니다.

익명 함수의 호출은 함수를 할당한 변수를 사용하여 호출합니다.

const multiply = function (a, b) {
	return a * b;
}
console.log(multiply(2, 3)); // 6

 

반대로 함수 이름이 포함된 기명 함수 표현식도 있습니다.

단, 기명 함수 표현식에서 정의한 함수의 이름은 함수의 몸체에서만 사용할 수 있습니다.

const multiply = function doSomething(a, b) {
	return a * b;
}

console.log(multiply(a, b)); // 6
console.log(doSomething(2, 3)); // Uncaught RegerenceError: doSomething is not defined

기명 함수 표현식에 사용된 함수의 이름은 외부에서 접근할 수 없기 때문에 함수의 이름으로 호출할 경우 마지막 줄처럼 ReferenceError가 발생합니다.

외부에서 함수 표현식을 호출할 경우 반드시 함수를 할당한 변수를 사용해야 한다는 것을 명심해야 합니다.

 

그렇다면 기명 함수 표현식은 어떤 경우에 사용할까요?

주로 함수 표현식을 재귀적으로 호출할 때 사용합니다.

const factorial = function doSomething(n) {
	return n <= 1 ? 1 : n * doSomething(n - 1);
}
console.log(factorial(5)); // 120

또한 함수 표현식은 함수 선언문과 달리 호이스팅이 되지 않기 때문에 함수에 함수를 할당하기 전에 호출할 수 없습니다.

console.log(multiply(2, 3)); // Uncaught TypeError: multiply is not a function

var multiply = function (a, b) {
	return a * b;
}

 

3) 함수의 호출

함수 선언문 또는 함수 표현식으로 함수를 정의하였다면 함수를 호출하여 실행할 수 있습니다.

함수 호출은 표현식이기 때문에 값으로 평가되며, 함수 몸체 안에 return 문을 사용하여 결과 값을 반환할 수 있습니다.

만약 return 문을 명시적으로 호출하지 않았다면 함수 호출의 결과 값은 undefined가 됩니다.

function greeting() {
	return 'Hello javascript';
}
console.log(greeting()); // 'Hello javascript'

▷매개변수(parameter)

함수를 정의하고 호출하여 값을 얻는 방법에 대해 알아보았습니다.

그렇다면 함수에 필요한 정보들을 전달하려면 어떻게 해야 할까요?

함수를 정의할 때 매개변수를 명시하여 정보들을 전달할 수 있습니다.

매개변수들함수 몸체에서 지역 변수처럼 사용됩니다.

참고로 백틱(``)을 써서 `${매개변수}` 형태로 몸체에서 사용 가능합니다.

// name이라는 매개변수를 명시하여 필요한 정보를 전달받을 수 있습니다.
function greeting(name) {
	// 백틱(``)을 사용합니다.
	return `Hello ${name}`;
}

 

 

자바스크립트는 느슨한 타입을 가진 언어이기 때문에 매개변수 역시 타입을 명시하지 않습니다.

또한 함수 호출 시 전달하는 인자의 값도 검사하지 않으며, 심지어는 인자의 개수도 검사하지 않습니다.

함수 호출 시 본래 정의된 매개변수보다 적은 수로 인자를 전달한다면 나머지 매개변수는 undefined 값으로 설정됩니다.

반대로 정의된 매개변수보다 많은 인자를 전달한다면 나머지 인자들은 무시됩니다.

 

[NOTE] 인자와 매개변수

인자와 매개변수는 동일한 의미 같지만 구분되어야 합니다.

인자함수 호출 시 전달되는 값을 의미하며, 매개변수함수에서 전달된 인자를 받아들이는 변수를 의미합니다.

영문으로도 인자는 argument, 매개변수는 parameter로 구분해서 사용합니다.

function greeting(name) {
	return `Hello ${name}`;
}

console.log(greeting()); // 'Hello undefined'
console.log(greeting('Lee', 'Han')); // 'Hello Lee'
  • 해체 할당과 매개변수 기본값

함수의 매개변수는 ES2015의 해체 할당과 매개변수 기본값을 사용하여 좀 더 편리하게 사용할 수 있습니다.

매개변수 해체 할당은 객체와 배열 모두 가능하며 프로퍼티가 없는 변수는 undefined를 할당 받습니다.

function getUserInfo({ name, age, country }) {
	return `name: ${name}, age: ${age}, country: ${country}`;
}

const userInfo = {name: 'Lee', age: 20};
console.log(getUserInfo(userInfo)); // 'name: Lee, age: 20, country: undefined'

매개변수에 해당하는 인자를 넘기지 않으면 매개변수의 값은 undefined로 설정됩니다.

만약 undefined가 아닌 기본값을 할당하고 싶을 경우 매개변수 기본값을 사용하여 지정할 수 있습니다.

function greeting(name = 'Lee') {
	return `Hello ${name}`;
}
console.log(greeting()); // 'Hello Lee'

 

▷arguments

화살표 함수를 제외한 모든 함수에서는 arguments라는 객체를 사용할 수 있습니다.

arguments객체를 사용하여 함수에 실제로 전달된 인자들을 참조할 수 있습니다.

또한 arguments객체는 유사 배열 객체이기 때문에 인덱스로 프로퍼티에 접근할 수 있으며, length 프로퍼티를 가지고 있습니다.

function sun(x, y, z) {
	console.log(arguments[0]); // 1
   	console.log(arguments[1]); // 2
   	console.log(arguments[2]); // undefined
   	console.log(arguments.length); // 2
    
   	return x + y + z;
}
sum(1, 2)

arguments객체는 ES2015부터 등장한 나머지 매개변수로 대체할 수 있습니다.

나머지 매개변수는 유사 배열 객체가 아닌 진짜 배열이기 때문에 인자들을 배열로 다루고 싶은 경우 유용하게 사용할 수 있습니다.

function sum(...args) {
	// args는 배열이기 때문에 배열 내장 메서드인 forEach()를 사용할 수 있습니다.
   	args.forEach(function (arg) {
   		// ...
    });
}
sum(1, 2);

 

+) 나머지 매개변수

나머지 매개변수 구문을 사용하면 함수가 정해지지 않은 수의 매개변수를 배열로 받을 수 있습니다.

function doSomething(a, b, ...args) {
	// ...
}

함수의 마지막 매개변수 앞에 '...'를 붙이면 모든 후속 매개변수를 표준 자바스크립트 배열에 넣도록 지정합니다.

 

4) 화살표 함수

화살표 함수는 ES2015에서 등장한 문법으로 기존의 함수 표현식에 비해 간결하게 함수를 정의할 수 있습니다.

화살표 함수는 항상 익명 함수이며, 아래와 같은 문법 특징이 있습니다.

 

- function 키워드를 생략합니다.

- 매개변수가 하나인 경우 괄호를 생략할 수 있습니다.

- 함수 몸체에서 문이 하나인 경우 중괄호({})나 return 키워드를 생략할 수 있습니다.

 

// function 키워드를 생략하였습니다.
const greeting1 = () => {return 'hello';};

// 매개변수가 name 하나이기 때무에 괄호를 생략하였습니다.
const greeting2 = name => {return `hello ${name}`;};

// 함수 몸체 내용이 return 문 하나이기 때문에 중활호와 return 키워드를 생략하였습니다.
const greeting3 = name => `hello ${name}`;

 

화살표 함수의 간결함은 배열의 map()과 filter() 메서드처럼 함수를 인자로 받는 경우에 매우 유용합니다.

arr.map(function (element, index) {
	return `${index}: ${element}`;
});
// 화살표 함수를 사용하면 익명 함수를 훨씬 간결하게 전달할 수 있습니다.
arr.map((element, index) => `${index}: ${element}`);

▷화살표 함수의 특징

화살표 함수는 일반 함수와 다른 점 두 가지가 더 존재합니다.

화살표 함수arguments 객체와 this를 바인딩하지 않기 때문에 기존 함수와는 다르게 동작합니다.

this에 대해서는 바로 다음에서 다룰 것입니다.

const func = () => arguments[0];
func(1); // Uncaught ReferenceError: arguments is not defined

화살표 함수에서는 나머지 매개변수를 사용하여 arguments객체를 대체할 수 있습니다.

const func = (...args) => args[0];
func(1); // 1

 

5) this

자바스크립트의 함수에서는 this라는 특별한 키워드를 사용할 수 있습니다.

this읽기 전용 값으로 런타임 시 설정할 수 없으며 함수를 호출한 방법에 의해 값이 달라집니다.

자바스크립트의 this 바인딩은 특히 헷갈리는 개념이니 어떻게 동작하는지 명확하게 이해해야 합니다.

▷일반 함수

일반 함수를 설명하기 앞서 먼저 전역 실행 컨텍스트에서의 this 바인딩을 보겠습니다.

전역 실행 컨텍스트에서의 this는 항상 전역 객체를 참조합니다.

전역 실행 컨텍스트는 자바스크립트 엔진이 코드를  실행할 때 처음으로 생성되는 컨텍스트입니다.

자바스크립트 코드가 실행되는 최상위 환경이라고 할 수 있습니다.

 

[NOTE]

전역 객체는 자바스크립트를 실행하는 환경마다 다릅니다.

브라우저 환경에서 자바스크립트를 실행한다면 window 객체가 전역 객체가 되며, Node.js 환경에서 실행하면 global 객체가 전역 객체가 됩니다.

 

console.log(this == window);

함수 선언문 또는 함수 표현식으로 정의한 함수를 호출할 경우 this 바인딩은 어떻게 될까요?

function func() {
	console.log(this == window); // true
}
func();

func() 함수 호출 시에도 마찬가지로 this의 값이 전역 객체를 참조합니다.

하지만 this는 window 전역 객체를 참조하는 것이 아니라 undefined로 남아 있어야 합니다.

window.func()처럼 메서드 호출이 아닌 func() 함수를 직접 호출하여 함수의 컨텍스트가 어디에 속하는지 알 수 없기 대문입니다.

하지만 this가 바인딩되지 않은 경우 기본 값으로 전역 객체를 참조하기 때문에 예제 코드와 같은 결과가 나옵니다.

이 문제는 자바스크립트의 엄격 모드를 사용하여 해결할 수 있습니다.

 

+) 바인딩

바인딩(Binding)이란 프로그램의 어떤 기본 단위가 가질 수 있는 구성요소의 구체적인 값, 성격을 확정하는 것을 말합니다.

const num = 123;

위 코드에서 const는 변수의 키워드, num은 변수의 이름, 123은 변수의 자료값입니다.

이처럼 이름, 자료형(키워드), 자료값에 각각 num, const, 123이라는 구체적인 값을 할당하는 각각의 과정을 바인딩이라고합니다.

함수에서도 바인딩이 일어나는데, 이때 바인딩은 어떤 코드에서 함수를 호출할 때 그 해당 함수가 위한 메모리 주소로 연결해주는 것을 의미합니다.

 

자바스크립트의 엄격 모드는 ES5에서 등장하였으므로, 언어의 중요한 문제점을 수정하고 엄격하게 오류를 검사하여 안전한 자바스크립트 작성을 도와줍니다.

'use strict' 지시문을 함수 본문 최상단에 넣어 엄격 모드를 활성화할 수 있습니다.

function func() {
	'use strict';
   	console.log(this == window); // false\
   	console.log(this == undefined); // true
}
func();

 

[NOTE]

엄격 모드에는 예시에서 설명한 것 이외에도 잠재적인 오류 방지를 위한 다양한 규칙들이 있습니다.

'use strict'
a = 1; // Uncaught ReferenceError: a is not defined

위의 코드는 엄격 모드에서 ReferenceError가 발생합니다.

엄격 모드가 아닌 경우 자바스크립트는 아무런 에러 없이 var a = 1; 을 실행한 것처럼 전역 변수를 선언하여 값을 할당합니다.

이러한 잠재적인 오류를 유발할 수 있는 코드는 엄격 모드에서 허용되지 않습니다.

엄격 모드에는 변수 사용과 보안에 관련된 다양한 규칙들이 있으니 자세한 내용은 MDN 또는 ECMAScript 명세를 참고하길 바랍니다.

 

엄격 모드에서는 this의 값이 window 전역 객체를 참조하지 않고 undefined로 올바르게 남아있는 것을 알 수 있습니다.

 

▷생성자 함수

new 키워드를 사용하여 함수를 호출하면 생성자 함수로 동작합니다.

생성자 함수의 this 바인딩은 일반 함수 호출과는 다르게 동작합니다.

function Vehicle(type) {
	this.type == type;
}
const car = new Vehicle('Car')

Vehicle() 생성자 함수를 호출하여 객체를 생성하였습니다.

생성자 함수를 호출하여 객체가 생성될 때 아래와 같은 단계로 동작합니다.

  • 객체를 생성하여 this에 바인딩

생성자 함수 내의 코드를 실행하기 전에 객체를 만들어 this에 바인딩합니다.

생성된 객체는 생성자 함수의 prototype 프로퍼티에 해당하는 객체를 프로토타입으로 설정합니다.

또한 이 객체는 이후 단계에서 this를 통해 계속 참조됩니다.

  • 프로퍼티 생성

this에 바인딩한 객체에 프로퍼티를 생성합니다.

function Vehicle(type) {
	this.type = type; // 프로퍼티 생성
}
  • 객체 반환

생성된 객체, this에 바인딩한 객체를 반환합니다.

또한 반환 값을 따로 명시하지 않아도 this에 바인딩한 객체가 반환됩니다.

다만, this가 아닌 다른 반환 값을 명시적으로 지정하였다면 this가 아닌 해당 값이 반환됩니다.

function Vehicle(type) {
	this.type = type;
   	return this; // 이 부분을 생략하여도 this에 바인딩한 객체가 반환됩니다.
}

생성자 함수 호출 시 객체가 생성되는 과정과 함께 this 바인딩이 어떻게 되는지 알아보았습니다.

그리고 이러한 과정은 반드시 new 키워드와 함께 생성자 함수를 호출한 경우에만 실행됩니다.

이 점을 반드시 기억합시다.

 

▷메서드

자바스크립트에서는 객체의 프로퍼티인 함수를 일반 함수와 구분하여 메서드라고 부르며, this 바인딩도 일반 함수와는 다르게 동작합니다.

메서드를 호출하면 this는 해당 메서드를 소유하는 객체로 바인딩됩니다.

const obj = {
	lang: 'javascript',
   	greeting() {
   		// this가 obj 객체로 바인딩됩니다.
		console.log(this);
		console.log(`hello ${this.lang}`;
    )
}
consolo.log(obj.greeting()); // 'hello javascript'

여기서 중요한 것은 메서드를 어떻게 호출했느냐에 따라 this 바인딩이 달라진다는 것입니다.

const obj = {
	lang: 'javascript',
   	greeting() {
   		return `hello ${this.lang}`;
	}
}
const greeting = obj.greeting;

console.log(greeting()); // 'hello undefined'

예제 코드처럼 메서드를 호출한다면 일반 함수를 호출했을 때와 동일하게 함수의 컨텍스트가 어디에 속하는지 알 수 없습니다.

이 경우 this는 전역 객체를 참조하거나 엄격 모드인 경우에는 undefined로 남아 있게 됩니다.

메서드를 의도한 대로 사용하기 위해서는 반드시 해당 객체의 컨텍스트(obj)로 명확하게 지정하여 호출해야 합니다.

 

▷call(), apply(), bind()

일반 함수, 메서드, 생성자 함수의 예시를 보면 자바스크립트가 내부적으로 this를 어떻게 바인딩하는지 알아보았습니다.

그렇다면 함수의 호출 방법에 상관없이 this를 특정한 객체로 바인딩할 수 없을까요?

자바스크립트에서는 함수의 내장 메서드인 call(), apply() 그리고 bind() 메서드를 이용하여 this로 바인딩될 객체를 변경할 수 있습니다.

그리고 이러한 방법을 명시적 바인딩이라고 부릅니다.

  • call(), apply()

call()과 apply() 메서드는 어떤 함수를 다른 객체의 메서드처럼 호출할 수 있게 합니다.

두 메서드는 넘겨받는 인자의 형식만 다를 뿐, this를 특정 객체에 바인딩하여 함수를 호출하는 역할을 합니다.

먼저 call() 메서드부터 보겠습니다.

const obj = { name: 'javascript' };

function greeting() {
	return `Hello ${this.name}`;
}

console.log(greeting.call(obj)); // 'Hello javascript'

call() 메서드는 첫 번째 인자로 this로 바인딩할 객체를 지정합니다.

obj 객체를 call() 메서드의 첫 번째 인자로 넘겨 this로 바인딩하였습니다.

greeting() 함수는 obj의 메서드처럼 사용할 수 있기 때문에 this를 통해 obj의 프로퍼티인 name에 접근할 수 있게 됩니다.

 

call() 메서드를 통해 호출하는 함수로 인자를 전달할 수도 있습니다.

const obj = { name: 'Lee'};

function getUserInfo(age, country) {
	return `name: ${this.name}, age: ${age}, country: ${country}`;
}
console.log(getUserInfo.call(obj, 20, 'Korea')); // 'name: Lee. age: 20, country: Korea'

call() 메서드의 첫 번째 인자 이후의 인자들은 모두 호출하는 함수로 전달됩니다.

 

apply() 메서드는 call() 메서드와 동일하지만 호출하는 함수에 전달할 인자들을 배열 형태로 전달해야 합니다.

const obj = { name: 'Lee' };

function getUserInfo(age, country) {
	return `name: ${this.name}, age: ${age}, country: ${country}`;
}
console.log(getUserInfo.apply(obj, [20, 'Korea'])); // 'name: Lee, age: 20, country: Korea'
  • bind()

함수의 this 바인딩을 변경할 수 있는 또 다른 방법으로 bind() 메서드를 사용하는 방법이 있습니다.

앞서 살펴본 call()과 apply() 메서드와는 두 가지 차이점이 있습니다.

 

- bind() 메서드는 함수의 this 바인딩을 영구적으로 변경합니다(생성자 함수로 사용되는 경우는 예외입니다). bind() 메서드로 this가 변경된 함수는 call(), apply() 또는 다른 bind() 메서드를 사용해도 this 바인딩을 변경할 수 없습니다.

- this를 바인딩하여 함수를 호출하는 것이 아니라 새로운 함수를 반환합니다.

 

bind() 메서드는 함수가 어디서 어떻게 호출되는지에 상관없이 this의 값을 고정하고 싶을때 사용합니다.

const obj1 = {name: 'Lee'};
const obj2 = {name: 'Han'};

function getUserInfo(age, country) {
	return `name: ${this.name}, age: ${age}, country: ${country}`;
}
const bound = getUserInfo.bind(obj1);

console.log(bound(20, 'Korea')); // 'name: Lee, age: 20, country: Korea'
console.log(bound.apply(obj2, [20, 'Korea'])); // 'name: Lee, age: 20, country: Korea'

bound() 함수는 this를 영구적으로 고정되었기 때문에 전역 컨텍스트에서 호출하든 apply() 메서드를 사용하여 호출하든 this의 값이 obj1로 고정됩니다.

 

bind() 메서드는 this뿐만 아니라 함수에 전달할 인자도 고정시킬 수 있습니다.

만약 getUserInfo() 함수로 전달되는 age 인자를 항상 20으로 고정하고 싶다면 아래처럼 변경할 수 있습니다.

const obj1 = {name: 'Lee'};

function getUserInfo(age, country) {
	return `name: ${this.name}, age: ${age}, country: ${country}`;
}

// getUserInfo 함수에 전달한 age 인자 값을 20으로 고정시켰습니다.
const bound = getUserInfo.bind(obj1, 20);

console.log(bound('Korea')); // 'name: Lee, age: 20, country: Korea'

bind() 메서드는 함수의 동작을 영구적으로 변경하므로 함수의 this가 어떻게 바인딩되는지 잘 파악하고 사용해야 합니다.

특히 call(), apply() 메서드를 사용하여 this를 변경해야 하는 경우 bind() 메서드로 this를 고정한다면 문제가 될 수 있으니 주의해야 합니다.

 

▷화살표 함수와 렉시컬 this

[화살표 함수]에서 화살표 함수는 this를 바인딩하지 않는다고 언급하였습니다.

화살표 함수는 this를 바인딩하지 않기 때문에 지금가지 설명한 this 바인딩의 규칙과는 완전히 다르게 동작합니다.

  • 렉시컬 this

함수 호출에 따라 동적으로 this를 바인딩하는 것이 아니라 함수를 어디에 선언하는지에 따라 this의 값이 결정됩니다.

화살표 함수의 this는 화살표 함수를 둘러싸고 있는 렉시컬 스코프에서 this의 값을 받아 사용합니다.

이러한 this를 렉시컬 this라고 하며 이 값은 변경되지 않습니다.

 

[NOTE]

렉시컬 스코프는 자바스크립트 엔진이 변수를 찾는 검색 방식에 대한 규칙이며, 함수를 어디에 선언했는지에 따라 결정됩니다.

 

const obj = {
	lang: 'javascript',
  	greeting: () => {
   		return `hello ${this.lang}`;
    }
}
console.log(obj.greeting()); // 'hello undefined'

greeting() 메서드를 화살표 함수로 정의하였습니다.

객체의 메서드 형태인 obj.greeting()으로 컨텍스트를 지정하여 호출하였음에도 불구하고 this를 통해 lang 프로퍼티에 접근하지 못합니다.

이는 화살표 함수의 렉시컬 this가 obj가 아닌 obj를 둘러싸고 있는 전역 컨텍스트에서 값을 받아오기 때문입니다.

전역 객체를 this로 가리키기 때문입니다.

  • 화살표 함수의 특징

화살표 함수는 this를 따로 바인딩하지 않고 변경되지 않는 렉시컬 this를 갖습니다.

이러한 특징 때문에 화살표 함수의 thiscall(), apply(), bind() 함수를 사용하여 변경할 수 없습니다.

const obj = { lang: 'javascript' };
const greeting = () => {
	return `hello ${this.lang}`;
};
// call() 메서드를 사용하여도 화살표 함수의 this는 변경되지 않고 전역 객체를 가리킵니다.
console.log(greerting.call(obj)); // 'hello undefined'

또한 화살표 함수는 생성자 함수로도 사용할 수 없습니다.

생성자 함수는 객체를 생성하여 this에 바인딩하지만, 화살표 함수는 렉시컬 this의 특징 때문에 이러한 동작을 할 수 없기 때문입니다.

 

화살표 함수는 정적인 렉시컬 this를 사용하기 때문에 기존의 동적인 this 바인딩의 혼잡함에서 벗어나 단순하게 사용할 수 있습니다.

특히 setTimeout()과 같은 전역 객체의 함수를 메서드에서 호출할 경우 화살표 함수를 사용하면 더욱 명확하게 간결하게 표현할 수 있습니다.

const obj = {
	name: 'javascript',
 	greeting() {
   		setTimeout((function timer() {
    		console.log(this.name);
        }).bind(this), 1000);
    }
}

setTimeout() 함수 내에서 실행되는 콜백 함수의 this는 전역 객체로 바인딩됩니다.

하지만 예제 코드에서는 bind() 메서드를 사용하여 this를 obj 객체로 변경한 새로운 함수를 사용했습니다.

이 예제 코드를 화살표 함수를 사용하여 간결하게 변경할 수 있습니다.

const obj = {
	name: 'javascript',
   	greeting() {
		setTimeout(() => {
      		console.log(this.name);
        }, 1000);
    }
}

화살표 함수는 자신을 둘러싸고 있는 렉시컬 스코프인 obj를 렉시컬 this로 참조하기 때문에 bind() 메서드를 사용하지 않아도 this를 obj 객체로 바인딩할 수 있습니다.

 


여기까지 자바스크립트 함수에 대해 알아보았습니다 :)

 

공부한 내용을 정리해보자면,

자바스크립트의 명시적, 암시적 타입 변환을 이해하는 것은 매우 중요합니다.

특히 암시적 타입 변환은 정해진 명세를 기준으로 동작하지만, 가독성 및 팀 컨벤션을 위해 타입 변환에 대한 명확한 규칙을 정하는 것이 좋습니다

또한 함수의 선언 방법과 특징 그리고 this 바인딩 과정에 대해서도 알아보았습니다.

특히 this 바인딩은 많은 개발자가 헷갈리는 부분이지만 한 가지만 명확하게 이해하면 됩니다.

this 바인딩은 함수 호출에 따른 컨텍스트에 따라 달라지며 call(), apply(), bind()와 같은 메서드를 사용하여 변경할 수 있다는 점입니다.

단 ES2015에서 등장한 화살표 함수는 이전의 함수 선언문, 함수 표현식과 다르게 렉시컬 this를 가지기 때문에 생성자 함수로 사용할 수 없으며, this 바인딩을 변경할 수 없습니다.

728x90
LIST
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함