함수 생성과 호이스팅

미마모코딩·2022년 4월 15일
1
post-thumbnail

호이스팅이란 무엇인가?

우리과 과거의 포스팅에서 다뤘듯이 코드의 선두로 끌어 올려진 것처럼 동작하는 것을 호이스팅이라고 한다.

코드로 예를 들어보자

<script>
console.log(add(2,5)) ; //7
console.log(sub(2,5)); // undifined

function add(x,y){
  return x + y;
}

var sub =function (x , y) {
  retutn x - y
} 

</script>

왜 add 함수에서는 값이 올바르게 나오고 sub은 값이 나오지 않는것일까?

위 예제와 같이 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출 할 수 있다.

그 이유는 함수 선언문이 제일 위로 끌어올려진 것처럼 동작하기때문에 선언 - 호출 의 순서로 작동하기 때문이다.

그렇다면 왜 sub은 undifined로 동작할까?

그이유는 변수 호이스팅에있다.

함수 표현식으로 함수를 정의하면 함수 선언문으로 정의 한게 아니기 때문에 변수 호이스팅이 발생한다.

즉 위에 코드에서의 sub는 아래 예제와 같이 동작한다.

<script>

function add(x,y){
  return x + y;
}

var sub;

console.log(add(2,5)) ; //7
console.log(sub(2,5)); // undifined
 

</script>

변수 호이스팅이 일어났기에 var sub 만 끌어올려진걸 알 수 있다 이렇게 동작하기에

변수 undifined가 값으로 참조되는 것이다.

화살표 함수

ES6에서 도입된 화살표 함수는 function 키워드 대신 화살표 => 를 사용해 조금 더

간략한 방법으로 함수를 선언할 수 있다.

화살표 함수는 항상 익명 함수로 정의한다.

화살표 함수의 코드 예제를 봐보자.

<script>
const add = (x,y) => x + y ;
console.log(add(2,5)); // 7
</script>

화살표 함수는 기존 함수와 this 바인딩 방식이 다르고 prototype 프로퍼티가 없으며

arguments 객체를 생성하지 않는다. 자세한 내용은 이후 포스팅에서 다루겠다.

자주쓰는 문법이니 화살표함수에 익숙해지려고 노력해보자.

매개변수와 인수의 관계

함수를 실행하기 위해 필요한 값을 함수 외부에서 함수 내부로 전달하는 상황이있다.

이러한 상황에서 매개변수(parameter)인자를 통해 인수(argument)를 전달한다.

인수는 값으로 평가될 수 있는 표현식이어야 한다.

인수는 함수를 호출할 때 지정하며 , 개수와 타입에 제한이 없다.

<script>
function add(x,y){
	return x + y;
}
var result = add(1,2)
</script>

이구조에서 코드의 동작의 순서는 이러하다.

1.add함수의 정의가 이루어졌다.

2.add 함수의 바디는 x + y의 연산을 마친후 값을 리턴한다.

3.add() 함수에 1,2 값을 넣어 호출한다.

4(1,2)를 넣은게 function add(x,y)코드의 x , y 자리에 순차적으로 값이 이동한다.

5.그리고 그 1 , 2 가 리턴문의 연산을 통해 값을 만들어낸다 . // 3

6.var result 라는 변수에 add(1,2) 함수를 할당해 var result는 3이된다.

매개변수의 참조

매개변수는 함수 몸체 내부에서만 참조할 수 있고,

함수 몸체 외부에서는 참조가 불가능하다.

즉 매개변수의 스코프(유효범위)는 함수 내부다 .

코드로 예를 들어보겠다.

<script>
 function add(x,y){
  console.log(x,y); // 2 5
  return x + y;
 }
 add(2,5);
 
 add함수의 매개변수 x,y는 함수 바디 내부에서만 참조할 수 있다.
 console.log(x,y) // ReferenceError : x is not defiend
</script>

이렇듯 함수의 매개변수는 바디안에서 참조할 수 있다는것을 기억해두자.

매개변수의 개수와 인수의 개수

함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않는다.

즉 함수를 호출할 때 매개변수의 개수만큼 인수를 전달하는것이 일반적이지만

그렇지 않은 경우에도 에러가 발생하지 않는다.

인수가 부족해서 인수가 할당되지 않은 매개변수의 값은 undifined다.

코드로 예를 들어보자.

<script>
 function add(x,y){
  return x + y;
 }

console.log(add(2));  // nan 2+undifined 기 때문에 not a number 출력
</script>

초과된 인수

코드를 입력하세요
<script>
 function add(x,y){
  return x + y;
 }
 console.log(add(2,5,9)) // 7
 </script>

초과된 인수는 그냥 버려지는 것이 아니다.

모든 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관된다.

함수의 인수확인

자바스크립트는 함수를 정의할 때 적절한 인수가 전달되었는지를 확인 할 필요가 있다.

아래 코드로 예시를 들어보자 .

<script>
function add (x,y){
if(typeof x !== "number" || typeof y !=="number" ){
// 매개변수를 통해 전달된 인수의 타입이 부적절할때 에러 발생
throw new typeError("인수는 모두 숫자 값이어야 합니다.")
}
return x + y ;
}
console.log(add(2)) // TypeError:인수는 모두 숫자 값이어야 합니다.
console.log(add("a","b")) //TypeError:인수는 모두 숫자 값이어야 합니다.
</script>

이처럼 typeof 를 통해 그 데이터 타입을 알아내 제어문으로 코드를 실행시킬수도 있다.

매개변수의 최대 개수

ECMAScript 사양에서는 매개변수의 최대 개수를 제한하고 있진 않다.

ECMA 스크립트란?

ECMA스크립트(ECMAScript, 또는 ES[1])란, Ecma International이 ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어를 말한다. 자바스크립트를 표준화하기 위해 만들어졌다. 액션스크립트와 J스크립트 등 다른 구현체도 포함하고 있다.[2] ECMA스크립트는 웹의 클라이언트 사이드 스크립트로 많이 사용되며 Node.js를 사용한 서버 응용 프로그램 및 서비스에도 점차 많이 쓰이고 있다. - 위키백과 출처

함수의 매개변수는 코드를 이해하는 데 방해되는 요소이다.

이상적인 매개변수의 개수는 0개이며 적을수록 좋다.

매개변수의 개수가 많다는 것은 함수가 여러가지 일을 한다는 증거이므로

바람직하지 않다.

이상적인 함수는 한 가지 일만 해야 하며 가급적 작게 만들것을 권장한다.

반환문 return

함수에서의 중요한 개념인 return 문에 대해 알아보자.

return 키워드는 표현식(반환값)으로 이루어진 반환문을 사용해 실행 결과를

함수 외부로 반환 할 수 있다.

코드로 예를 들어보자.

<script>
function multiply(x,y){
return x * y; // 반환문
}
//함수 호출은 반환값으로 평가된다.
var result = multiply(3,5);
console.log(result); // 15 
</script>

위 함수는 두 개의 인수를 전달받아 곱한 결과값을 return 키워드를 통해 반환한다.

그 반환한 값을 var result에 할당했기때문에 var result는 콘솔에서 15라는 값이 나온다.

함수의 마지막 문 실행 후 암묵적인 동작

함수에서 반환문은 생략할 수 있다.

이때 함수는 함수 몸체의 마지막 문까지 실행하고 암묵적으로 undifined를 반환한다.

코드로 예를 들어보자.

<script>
function foo(){
return;
}
console.log(foo()); // undifined
</script>

이코드에서 알 수 있듯이 정말 중요한 개념이다 .

함수 내부의 코드안에서 문이 다 실행되면 암묵적으로 undifined를 반환한다.

아마 초심자한텐 도대체 어디서 undifined가 나온거야! 라고 생각 할 수 있을 것이다.

이럴땐 대부분 return을 생략해서 발생한 문제이므로 참고하자.

참조에 의한 전달과 외부 상태변경

원시값은 값에 의한 전달 , 객체는 참조에 의한 전달 방식으로 동작한다.

매개변수도 함수 몸체 내부에서 변수와 동일하게 취급되므로 매개변수또한

타입에 따라 값에 의한 전달 , 참조에 의한 전달 방식을 그대로 따른다

이렇게 말하면 어려우니 코드로 바로 확인해보자.

<script>
//매개변수 primitive는 원시 값을 전달받고, 매개변수 obj는 객체를 전달받는다.
function changeVal(primitive,obj){
primitive += 100;
obj.name = "Kim"
}

//외부상태
var num = 100;
var person ={name:"Lee"};

console.log(num) ; //100
console.log(person) //{name:"Lee"};

changeVal(num,person) // 원시 값은 값 자체가 복사되고 객체는 참조 값이 복사되어 전달

console.log(num) ; //100 원시값은 원본이 훼손되지 않는다.
console.log(person) ; //{name:"Kim"} 객체는 원본이 훼손된다.


</script>

동작 원리 대해서 설명하겠다.

1.changeVal함수의 정의가 이루어졌다.

2.changeVal함수는 원시갑과 객체를 매개변수로 받는다.

3.외부에서 만든 전역변수 var num = 100;

4.외부에서 만든 전역객체 var person 의 키값(name) 벨류값은 ("Lee")이다.

5.콘솔에 찍었을땐 3,4 번이 그대로 잘 나온다.

6.changeVal함수의 인수로 num,person을 넣었다.

7.인수 num,person은 changeVal함수의 primitive,obj 로 차례대로 들어간다.

8.그 상태에서 콘솔 console.log(num)을 하게되면 원시값이기 때문에 원본의 훼손이 일어나지 않는다.

9.console.log(person)에서는 우리가 넣은게 Lee 기 때문에 Lee가 나와야하지만 우리가 먼저 changeVal함수에서 정읠한 obj.name의 영향을 받아 Lee가 아닌 Kim이 출력된다. 이를통해 객체는 원본이 훼손된다라는것을 알 수있다.

오늘은 여러가지 함수의 개념에 대해 알아보았다.

다음시간엔 즉시실행함수의 대해 알아볼것이다.

0개의 댓글