[Effective JavaScript] 기명함수 표현식의 스코프에 주의하자

김범식·2023년 6월 25일
0

Effective JavaScript

목록 보기
12/33
post-thumbnail
function double(x){return x*2}

이 함수는 선언문이 될 수도있고 기명함수 표현식이 될 수 도 있다. 선언문이 된다면 호이스팅되어 전역으로 사용될 것이다.

var f = function double(x){return x*2)

함수를 변수 f에 바인딩 한다.

물론 이름을 지정할 필요는 없다.

var f = function(x){return x*2}

기명함수 표현식은 익명함수 표현식과 달리 그 이름을 함수 내의 지역변수로 바이딩한다는 공식적인 차이점이 있다. 이특징을 재귀함수를 작성하는데 사용할 수 있다.

var f = function find(tree, key){
	if(!tree){
		return null
	}
	if(tree.key == key){
		return tree.value;
	}
//왼쪽에서 나오면 왼쪽 tree.value, 아니라면 오른쪽 tree.value 그것도 아니라면 null 반환
	return find(tree.left, key) || find(tree.right, key); 
}

내부에서 재귀함수를 사용할 때는 find라는 이름을 사용할 수 있지만 외부에서는 사용할 수 없다.

find(myTree, "foo") //에러남 

물론 외부스코프 이름을 사용할 수도 있다.

var f = function(tree, key){
	if(!tree){
		return null
	}
	if(tree.key == key){
		return tree.value;
	}
	return f(tree.left, key)|| f(tree.right, key);
}

아니면 단순하게 선언문을 사용해도 좋다.

function find(tree, key){
	if(!tree){
		return null
	}
	if(tree.key == key){
		return tree.value;
	}
//왼쪽에서 나오면 왼쪽 tree.value, 아니라면 오른쪽 tree.value 그것도 아니라면 null 반환
	return find(tree.left, key) || find(tree.right, key); 
}

var f = find;

이러한 기명함수 표현식은 디버깅할 때 정말로 유용하다. 대부분 최신 자바스크립트 실행환경은 Error 객체를 위해 스택추적(stack trace)을 만들고 함수 표현식의 이름은 보통 스택 추적내의 엔트리로 사용된다.

기명함수 표현식의 스코프를 객체로 표현해야 한다, 이로인해 생성시 문제를 일으킬 소지가 많았다. 이 스코프객체는 그 함수의 이름을 바인딩하는 하나의 프로퍼티만을 가지지만, 당연히 Object.prototype의 프로퍼티들을 상속 받았다. 이는 함수 표현식에 이름을 짓는 것만으로 Object.prototype의 모든 프로퍼티가 해당 스코프 안으로 들어온다는 뜻이다.

Object.prototype이란 javascript에서 모든 객체가 상속받는 객체이다.

var constructor = function(){return null};
var f = function(){
	return constructor();
};
f(); // {} 새로운 객체 생성 (ES3 실행 환경)

null을 반환할 것처럼 보이지만, 기명함수 표현식이 Object.prototype.constructor(즉 Object생성자 함수)를 상속하기 때문에 실제로는 새로운 객체를 만들어 낸다.

고맙게도 ES5에서는 이실수를 수정했다.

하지만 몇몇 자바스크립트 실행환경은 여전히 잘못된 스코프 방식을 고수하고 있다.

var constructor = function(){return null};
var f = function(){
	return constructor();
};
f(); // {} // 표준을 따르지 않는 실행환경

함수표현식의 스코프를 객체로 오염시키는 이런문제를 피할 수 있는 최선의 방법은 Object.prototype에 새로운 프로퍼티를 절대 추가하지 않고 지역변수에 표준 Object.prototype 프로퍼티의 어떠한 이름도 사용하지 않는것이다.

var f = function g() {return 17;}
g(); //17

//물론 지금은 이러지 않음, 에러남 

다음은 유명한 버그로 이는 명백히 표준을 제대로 준수하지 않는 동작이다. 이러한 불편을 막기위해서는 다음과 같은 차선책이 있다.

var f = function g() {return 17;}
var g = null;

변수를 var로 재선언하면 함수 표현식을 오류로 호이스팅하는 실행환경에서도 g가 바인딩 되는것을 보장하고, 값을 null로 지정하면 복제된 함수가 가비지컬렉션의 대상이 되게한다.

기명함수 표현식을 사용하기에는 너무 문제가 많다고 결론짓는건 당연하다. 때문에 모든 함수를 익명으로 만다는것이좋다.

기억할점

  • Error객체와 디버거에서 스택 추적을 개선하기 위해 기명함수 표현식을 사용하라
  • ES3과 버그가 있는 자바스크립트 실행환경에서 함수 표현식이 스코프를 Object.prototype으로 오염시킨다는점을 주의하라
  • 버그가 있는 자바스크립트 실행환경에서 기명함수 표현식의 호이스팅과 중복 할당을 주의하라
  • 기명함수 표현식의 사용을 자제하고 ,배포하기전에 제거하라
  • ES5를 제대로 구현한 실행환경에 배포한다면, 아무런 걱정을 할 필요가 없다.
profile
frontend developer

0개의 댓글