자바스크립트 — 함수

chrisjune
chrisjune
Published in
10 min readMay 6, 2019

더글라스 크락포드의 자바스크립트 핵심가이드를 정리한 문서입니다.

총 10장으로 이루어진 책으로 한 장씩 정리하여 포스팅할 예정입니다.

본 책은 자바스크립트의 좋은 점만을 정리한 책으로, 나쁜 점을 잊어야 할 수고를 덜 수 있습니다.

1. 함수객체

함수는 일급객체로서 하나의 값으로 평가됩니다. 객체리터럴을 생성하면 Object.prototype에 연결되고, 함수리터럴을 생성하면 Function.prototype을 부모로 상속받아 연결되어있습니다.

자바스크립트에서는 클래스가 없기 때문에 function으로 생성자의 역할을 할 수 있습니다. 이때, 첫글자만 대문자로 사용(Pascal case)를 반드시 지켜야합니다.

2. 함수 구성요소

함수는 function <name> (매개변수...) {} 총 네개의 요소로 구성되어있습니다.

function Person(name) {
var name = name;
}

3. 함수호출

함수를 호출하면 내부적으로 thisarguments 라는 인자를 받습니다.

  • this는 호출시 컨텍스트의 객체를 의미합니다.

* arguments는 매개변수 리스트객체(실제, 리스트는아니고 리스트 유사한 객체임)를 의미합니다.

  • 호출시, 파라미터 갯수가 함수의 파라미터보다 많으면 over 되는 파라미터는 무시되지만, arguments 배열에는 모두 포함됩니다.
  • 호출시, 파라미터 갯수가 함수의 파라미터 보다 적으면, undefined로 처리됩니다.

자바스크립트에서는 호출 패턴에 따라서 this의 값이 달라집니다

3–1) 메소드 호출패턴

객체의 속성인 함수를 메소드라고 합니다. 메소드인 함수를 호출할 때 특징입니니다. 메소드가 호출될 때, thislazy binding되고 자신을 포함하는 객체의 속성에 접근이 가능합니다.

var myObject = {
value : 0,
increment: function(inc){
this.value += typeof inc === 'number' ? inc : 1;
}
};
console.log(myObject.increment());
// this = myObject

3–2) 함수 호출패턴

객체의 속성으로 지정되지 않는 함수를 호출하는 경우입니다. 이때 함수는 Global 객체를 가르키고 있습니다. 특히, 중첩함수에서는 내부함수가 외부함수에 접근하기 위하여 외부함수의 this를 관례적으로 that 변수에 저장하여 활용합니다

myObject.double = function(){
var that = this;
var helper = function(){
// that --> myObject
that.value = add(that.value, that.value);
}
helper();
};

myObject.double()
console.log(myObject.value);

3–3) 생성자 호출 패턴

생성자는 다른 객체를 생성하는데 사용되는 함수를 의미합니다. 전치연산자인 new를 반드시 사용합니다. 또한 Pascal case(첫글자 대문자)를 사용합니다.

생성자 호출은 return 값이 객체가 아니라면, 일반적으로 생성자 객체를 반환합니다

var Human(){};
var chrisjune = new Human();
chrisjune.__proto__ === Human.prototype; // true
chrisjune.__proto__.constructor === Human // true

var Quo = function(string){
this.status = string;
}
Quo.prototype.get_status = function(){
return this.stauts;
}
var myquo = new Quo('content');
myquo.status; // content

3–4) Apply, Call 호출 패턴

applycall 함수를 사용하면, 함수가 실행될 때 가르킬 this 객체를 지정할 수 있습니다. 첫번째 인자는 this, 두번째 객체는 매개변수를 넘겨줍니다

function print(){
return this.toString();
}

var obj = {
print:print,
toString: function(){
return '[object obj]';
}
};

print(); //"[object Window]"
obj.print() //"[object obj]"
print.call(obj) //"[object obj]"
print.apply(obj) //"[object obj]"
obj.print.call() //"[object Window]"
obj.print.call(obj) //"[object obj]"
obj.print.apply(); //"[object Window]"
obj.print.apply(obj)//"[object obj]"

4. 기본 타입에 기능 추가

Object, Function, Array .. 등등 기본 타입에 기능추가가 가능합니다

프로토타입에 의한 상속이라는 동적연결로, 기능을 향후에 추가해도 이미 생성한 객체에서 모두 사용가능합니다.

Function.prototype.method = function(name, func){
this.prototype[name]=func;
return this;
}

Number.method('integer', function(){
return Math[this<0 ? 'ceil' : 'floor'](this);
});

console.log((10/3).integer()); // 3

Number.method 안의 this는 (10/3)값을 가진 Number 객체입니다.

Function.prototype안의 this는 (10/3).integer()함수가 실행될 때 Number 객체로 바인딩됩니다. 자바스크립트는 이와같이 this가 함수가 호출될 때 lazy binding이라는 특성을 가집니다.

5. 클로저 (Closure)

함수의 매개변수와 지역변수를 참조할 수 있고, 이미 함수가 return 된 상태에서도 접근 가능한 것을 클로져라고 합니다.

자바스크립트에서는 특정구문(function, with, catch)이 실행되거나 객체들이 생성될 때마다 고정적인 유효범위가 생성되고 이를 스코프 체인이라고 합니다.

함수가 종료되어도, 언제든 스코프체인으로 묶여있는 값은 고정적이기 때문에 이를 Closure라고 부릅니다.

예제코드 1

var myObj = function(){
var value = 0;
return {
increment: function (inc){
value += typeof inc === 'number' ? inc : 1;
},
getValue:function(){
return value;
}
};
}();

위 함수는 myObject라는 객체에 increment와 getValue라는 함수를 추가하는 코드입니다. value라는 변수는 지역변수로서 함수가 종료되고나서 외부에서는 접근할 수 없습니다. 그러면 객체의 값을 어떻게 가져올 수 있을 까요?

getValue라는 함수가 이 값을 반환하도록 함수를 작성하고 이를 반환하도록 하는 함수를 실행하였습니다. 이때 스코프 체인이 생성되어 getValue함수는 언제든 value값에 접근이 가능하게 됩니다.

예제코드 2

Div 요소 세개를 만들고 클릭하면 본인의 index를 alert창으로 보여주는 코드입니다.

<div id="div0">Click me Div 0</div>
<div id="div1">Click me Div 1</div>
<div id="div2">Click me Div 2</div>

<script>
var i, len = 3;
for (i = 0; i < len; i++){
document.getElementById('div'+i).addEventListener('click',
function(){
alert('You clicked div #'+i);
}
, false);
}
</script>

Click me Div 0을 클릭하면 어떻게 될까요?

크롬에서 실행결과

You clicked div #0 이라는 예상과는 다르게 출력이 됩니다. 그 이유는 div를 클릭할 때 전역변수인 i를 가르키고있고, 현재 루프가 종료된 상태이기 때문에 3을 출력하게 됩니다.

그러면, 어떻게 i 값을 이벤트에 고정시킬수 있을까요? 클로져를 사용하여 문제를 해결해보도록 하겠습니다

<div id="div0">Click me Div 0</div>
<div id="div1">Click me Div 1</div>
<div id="div2">Click me Div 2</div>

<script>
var i, len = 3;
for (i = 0; i < len; i++){
document.getElementById('div'+i).addEventListener('click',
function(i){
return function(){
alert('You clicked div #'+i);
}
}(i)
}
</script>

alert()를 반환하는 함수에 index값을 매개변수로 전달하고 이 함수를 실행시켜서 스코프 체인을 생성하였기 때문에 i 값은 전역변수인 i가 아닌 매개변수인 i를 가르키고 있습니다

여기서 만약 return function(){alert()}가 아닌 alert()로 한다면, 페이지가 로딩 되자마자 클릭전에 alert메시지가 실행됩니다.

예제코드 3

// https://www.google.com/ console에서 실행

var google_div = document.getElementsByClassName('content')[0];
google_div.name='Google'

var event = {
name: 'event',
say: function(e){
alert('Hello '+ this.name);
}
}

google_div.addEventListener('click', event.say); // this → google

구글 로고 여백을 클릭하면 아래와 같은 메시지가 실행됩니다

만약, event객체인 name을 출력하고 싶으면 어떻게 해야할까요? 아래 처럼 event.say 메소드를 클로져로 만들어서 이벤트로 추가하면됩니다!

google_div.addEventListener('click', function () {
return event.say();
});

참고

--

--