Function and Prototype Chaning


= Function and Prototype Chaning :doctype: book :icons: font :source-highlighter: coderay :toc: top :toclevels: 3 :sectlinks: :numbered: :sectnums!: == Intro 함수에서 가능한 동작:: - 리터럴에 의해 생성 - 변수나 배열의 요소, 객체의 프로퍼티 등에 할당 - 함수의 인자로 전달 - 함수의 리턴값으로 리턴 - 동적으로 프로퍼티를 생성 및 할당 :sectnums: == 함수 정의 - 함수 선언문 ^function-statement^ - 함수 표현식 ^function-expression^ - Function() 생성자 함수 === 함수 리터럴 - 함수도 일반 객체처럼 값으로 취급 - ``객체 리터럴`` 방식으로 일반 객체를 생성할 수 있는 것처럼 ``함수 리터럴``을 이용해 함수를 생성할 수 있음 [source, javascript] ---- function add(x, y) { return x + y; } ---- <1> ``function`` 키워드: 함수 리터럴은 ``function`` 키워드로 시작 <2> 함수명: 함수를 구분하는 식별자로 선택 사항(이름이 없으면 익명 함수) <3> 매개변수 리스트: 함수를 호출할 때 사용하는 매개변수로 타입을 기술하지 않음 <4> 함수 몸체: 함수가 호출될 때 실행되는 코드 <<<< === 함수 선언문 - 함수 리터럴 형태 - ``함수 선언문 방식``으로 정의된 함수는 **반드시 함수명이 정의되어 있어야 한다.** - 매개변수 타입과 리턴 타입을 명시하지 않음 [source, javascript] ---- // add() 함수 선언문 function add(x, y) { return x + y; } console.log(add(3, 4)); // 출력값: 7 ---- **자바스크립트 엔진에 의해 다음과 같이 변형** [source, javascript] ---- var add = function add(x, y) { return x + y; }; ---- <<<< === 함수 표현식 - 함수도 하나의 값처럼 취급되고 이 특징때문에 자바스크립트의 함수는 ``일급 객체^first-class-citizens^``라 함 - 변수에 할당 가능 - 함수 명이 없으므로 ``익명함수`` ==== 익명 함수^anonymous-function^를 이용한 함수 표현식 [source, javascript] ---- // add() 함수 표현식 var add = function (x, y) { <1> return x + y; }; var plus = add; <2> console.log(add(3, 4)); // 출력값: 7 <3> console.log(plus(5, 6)); // 출력값: 11 <4> ---- <1> **add** 변수는 함수 이름이 아니라 함수 리터럴로 생성한 함수를 참조하는 변수 <2> **add**가 참조하는 함수의 참조값을 **plus** 변수에 할당 <3> **add** 변수가 참조하는 함수를 호출 <4> **plus** 변수가 참조하는 함수를 호출(**add**와 같은 함수를 호출) <<<< ==== 기명 함수 표현식 [source, javascript] ---- var add = function sum(x, y) { <1> return x + y; } console.log(add(3, 4)); // 출력값: 7 <2> console.log(sum(3, 4)); // 출력값: Uncaught ReferenceError: sum is not defined <3> ---- <1> **sum()** 함수를 정의하고, 이 함수를 **add** 변수에 할당 <2> **add** 변수에 할당된 함수 호출 <3> **sum** 함수를 호출, 에러 발생 [%hardbreaks] - ``함수 표현식``에 사용된 함수 이름은 함수 내부에서 재귀적으로 호출하거나, ``디버거``에서 함수를 구분할 때 사용 TIP: ``재귀함수``: 함수 내부에서 자기 자신을 다시 호출 [source, javascript] ---- var factorialVar = function factorial(n) { if(n <= 1) { return 1; } return n * factorial(n-1); <1> }; console.log(factorialVar(3)); // 출력값: 6 <2> console.log(factorial(3)); // 출력값: Uncaught ReferenceError: factorial is not defined <3> ---- <1> 함수 내부에서 함수 선언문에서 함수 이름으로 사용한 **factorial** 함수를 사용 <2> 함수 외부에서 **factorialVar**이 참조하는 함수를 호출 <3> 함수 외부에서 **factorial** 함수를 호출 .``function statement``와 ``function expression``에서의 세미콜론 [NOTE] ==== 자바스립트 코드를 작성할 때 ``함수 선언문`` 방식으로 선언된 함수는 함수 끝에 세미콜론(;)을 붙이지 않지만, ``함수 표현식`` 방식은 세미콜론(;)을 붙이는 것을 권장한다. [source, javascript] ---- var func = function() { return 42; } // 세미콜론을 사용하지 않음 (function() { console.log("function called"); })(); ---- 위 코드에서 **func** 함수의 끝에있는 **중괄호(})**만으로 함수가 끝났다고 판단하지 않고, 그 뒤의 소괄호를 함수를 실행한다는 의미로 해석하여 에러가 발생 ==== <<<< === Function() 생성자 함수 [source, javascript] ---- var add = new Function('x', 'y', 'return x + y'); console.log(add(3, 4)); // 출력값: 7 ---- <<<< === 함수 호이스팅^function-hoisting^ - ``함수 선언문`` 방식을 사용하면 함수를 선언하기 전에 함수 호출 가능 - **더글러스 크락포드**는 ``함수 호이스팅``은 함수를 사용하기 전에 반드시 선언해야 한다는 규칙을 무시하여 ``함수 표현식`` 사용을 권장 [source, javascript] ---- add(2, 3); // 5 <1> // 함수 선언문 형태로 add() 함수 정의 function add(x, y) { <2> return x + y; } add(3, 4); // 7 <3> ---- <1> 함수가 정의되기 전에 함수 호출 <2> 함수 정의 <3> 함수가 정의된 후 함수 호출 [source, javascript] ---- add(2, 3); // uncaught type error <1> // 함수 표현식 형태로 add() 함수 정의 var add = function (x, y) { <2> return x + y; }; add(3, 4); // 7 <3> ---- <1> 함수가 정의되기 전에 함수 호출 <2> 함수 정의 <3> 함수가 정의된 후 함수 호출 [%hardbreaks] - ``함수 호이스팅``이 발생하는 원인은 **변수 생성^instantiation^**과 **초기화^initialization^** 작업이 분리되어 진행되기 때문 * **5장**에서 자세히... <<<< == 함수 객체 === 함수도 객체다 - 함수는 코드 실행뿐만 아니라, 일반 객체처럼 프로퍼티를 가질 수 있음 [source, javascript] ---- // 함수 선언 방식으로 add()함수 정의 function add(x, y) { <1> return x + y; } // add() 함수 객체에 result, status 프로퍼티 추가 add.result = add(3, 2); <2> add.status = 'OK'; <3> console.log(add.result); // 출력값: 5 console.log(add.status); // 출력값: OK ---- <1> 함수를 생성할 때 함수 코드는 함수 객체의 ``[ [Code] ]`` 내부 프로퍼티에 자동으로 저장 <2> 일반 객체처림 result 프로퍼티를 생성하고, **add()** 함수를 호출한 결과를 저장 <3> status 프로퍼티를 생성하고 문자열을 저장 <<<< === 함수는 값으로 취급된다 함수에서 가능한 동작:: - 리터럴에 의해 생성 - 변수나 배열의 요소, 객체의 프로퍼티 등에 할당 - 함수의 인자로 전달 - 함수의 리턴값으로 리턴 - 동적으로 프로퍼티를 생성 및 할당 위와 같은 특징으로 인해 ``일급 객체^first-class-citizens^``라고 부르고, 이런 특징으로 인해 ``함수형 프로그래밍``이 가능하다. (**7장**에서 자세히...) [quote, 'https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B8%89_%EA%B0%9D%EC%B2%B4[Wikipedia]'] ____ 특정 언어의 일급 객체 (first-class citizens, 일급 값, 일급 엔티티, 혹은 일급 시민)이라 함은 컴퓨터 프로그래밍 언어 디자인에서 일반적으로 다른 객체들에 적용 가능한 연산을 모두 지원하는 객체를 가리킨다. 함수에 매개변수로 넘기기, 변수에 대입하기와 같은 연산들이 여기서 말하는 일반적인 연산의 예에 해당한다. 직관적으로 설명하자면, Function 이면서 Class의 성질인 지닌 객체 또는 Class이면서 Function의 성질을 지닌 객체를 First-Class Citizens 라고 이해할 수 있다. JavaScript 에서 Function에 Property를 줄 수 있는 것이 대표적인 예이다. ____ <<<< ==== 변수나 프로퍼티의 값으로 할당 [source, javascript] ---- var bar = function() { return 100; }; console.log(bar()); // 출력값: 100 // 프로퍼티에 함수 할당 var obj = {} obj.baz = function() { return 200; } console.log(obj.baz()); // 출력값: 200 ---- ==== 함수 인자로 전달 [source, javascript] ---- // 함수 표현식으로 foo() 함수 생성 var foo = function(func) { func(); }; // foo() 함수 실행 foo(function() { console.log('Function can be used as the argument.'); }); // 출력값: Function can be used as the argument. ---- <<<< ==== 리턴값으로 활용 [source, javascript] ---- // 함수를 리턴하는 foo() 함수 정의 var foo = function() { return function() { console.log('this function is the return value.'); }; }; var bar = foo(); bar(); // 출력값: this function is the return value. ---- <<<< === 함수 객체의 기본 프로퍼티 [source, javascript] ---- function add(x, y) { return x + y; } console.dir(add); ---- ---- ƒ add(x, y) arguments: null caller: null length: 2 name: "add" prototype: constructor: ƒ add(x, y) __proto__: Object __proto__: ƒ () apply: ƒ apply() arguments: (...) bind: ƒ bind() call: ƒ call() caller: (...) constructor: ƒ Function() length: 0 name: "" toString: ƒ toString() Symbol(Symbol.hasInstance): ƒ [Symbol.hasInstance]() get arguments: ƒ () set arguments: ƒ () get caller: ƒ () set caller: ƒ () __proto__: Object [[FunctionLocation]]: [[Scopes]]: Scopes[0] [[FunctionLocation]]: VM528:1 [[Scopes]]: Scopes[1] ---- - 모든 함수가 ``length``와 `prototype` 프로퍼티를 가져야 함 - `name` 프로퍼티: 함수 이름 - `caller` 프로퍼티: 자신을 호출한 함수 - `arguments` 프로퍼티: 함수를 호출할 때 전달된 인자값 - `length` 프로퍼티: 함수 인자의 수 - `__proto__` 프로퍼티: ``[ [Prototype] ]`` 내부 프로퍼티, 부모역할을 하는 객체 - `prototype` 프로퍼티: 객체로서의 프로퍼티 [NOTE] ==== .arguments 객체 arguments 프로퍼티와 같은 이름으로 ECMA 표준에서는 arguments 객체를 정의하고 있다. arguments 객체는 함수를 호출할 때 호출된 함수의 내부로 인자값과 함께 전달되며, arguments 프로퍼티와 유사하게 함수를 호출할 때 전달한 인자값의 정보를 제공해준다. (**4.4.1 arguments 객체**에서...) ==== <<<< ==== prototype 프로퍼티 - 함수가 생성될 때 생성 - `constructor` 프로퍼티 하나만 있는 객체 - 함수와 함수의 `prototype` 프로퍼티는 상호참조 - 내부 프로퍼티인 ``[ [Prototype] ]``과는 다른 것 * **4.5.1 프로토타입의 두 가지 의미**에서 자세히... [TIP] ==== .`Function.prototype` 객체의 프로토타입 객체는? 명제:: 1. 모든 함수들의 부모 객체는 `Function Prototype` 객체 2. `ECMAScript` 명세서에서 ``Function.prototype``은 함수라고 정의 => `Function.prototype` 함수 객체도 `Function Prototype` 객체? ==> `ECMAScript` 명세서에서 `Function.prototype` 함수 객체의 부모는 모든 개게의 조상격인 `Object.prototype` 객체라 정의 ==== Function.prototype 객체가 가지는 프로퍼티와 메서드:: - constructor - toString() - apply(thisArg, argArray) - call(thisArg, [, arg1 [, arg2, ]]) - bind(thisArg, [, arg1 [, arg2, ]]) - ``apply()``, ``call()``은 자주 사용되므로 **4.4.2.4 call과 apply 메서드를 이용한 명시적 this 바인딩** 에서 자세히... <<<< == 함수의 다양한 형태 === 콜백 함수 - ``익명함수``의 대표적인 용도 - 개발자가 등록하고 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 시스템에서 호출되는 함수 - 특정 함수의 인자로 넘겨서, 코드 내부에서 호출되는 함수 - 대표적으로 ``이벤트 핸들러`` 처리에 사용 [source, html] ---- ---- <<<< === 즉시 실행 함수^immediate-functions^ - 최초 한 번의 실행만을 필요로 하는 초기화 코드 부분에 사용 - 한 번 사용 후 다시 사용할 수 없음 - 특정 범위 내에서만 변수를 사용하거나(함수 유효 범위), 변수 접근을 막기 위해 사용 * **5장**에서 자세히... [source, javascript] ---- (function (name) { <1> console.log('This is the immediate function -> ' + name); <2> })('foo'); <3> ---- <1> 함수 정의 <2> 함수 본문 <3> 함수 정의 완료 및 실행 .즉시 실행 함수 기타 예시 [source, javascript] ---- if (typeof window.jQuery === 'undefined') { throw new Error('this lib require jQuery'); } +function (factory) { 'use strict'; window.lib = factory(jQuery); }(function ($) { 'use strict'; ... var lib = function(options) { ... } .. return lib; }); ---- <<<< === 내부 함수^inner-function^ - 함수 내부에 함수를 정의 - ``클로저`` * **5장**에서 자세하게... - 부모함수 코드에서 외부에서의 접근을 막고 독립적인 ``헬퍼 함수``를 구현하는 용도 [source, javascript] ---- // parent() 함수 정의 function parent() { var a = 100; var b = 200; // child() 내부 함수 정의 function child() { var b = 300; console.log(a); console.log(b); } child(); } parent(); child(); ---- .출력결과 ---- 100 300 Uncaught ReferenceError: child is not defined ---- - 내부함수에서 a는 선언하지 않았지만 100이 출력되고 b가 200이 아니라 300이 출력된 이유는 `스코프 체이닝` 떄문 * **5장**에서 자세히... - 내부 함수는 자신을 둘러싼 외부 함수의 변수에 접근이 가능 .클로저 예시 [source, javascript] ---- function parent() { var a = 100; // child() 내부 함수 var child = function () { console.log(a); } return child; } var closure = parent(); closure(); <1> ---- - 실행이 끝난 부모 함수 스코프의 변수를 참조하는 함수 * **5장**에서 자세히... <<<< === 함수를 리턴하는 함수 - 함수를 호출함과 동시에 다른 함수로 바꾸거나, 자기 자신을 재정의하는 함수를 구현할 때 사용 [source, javascript] ---- // self() 함수 var self = function() { console.log('a'); return function() { console.log('b'); } }; self = self(); // 출력값: a self(); // 출력값: b ---- <<<< :sectnums!: == References - . 송현주 . 고현준 INSIDE JavaScript(인사이드 자바스크립트) . 한빛미디어, pp. 71-98