// 함수의 정의(함수 선언문)
function square(number) {
return number * number;
}
// 함수의 호출
square(2); // 4
function square(number) {
return number * number;
}
- 무명의 리터럴로 표현이 가능하다.
- 변수나 자료구조(객체, 배열...)에 저장할 수 있다.
- 함수의 파라미터로 전달할 수 있다.
- 반환값(return value)로 사용할 수 있다.
// 함수 표현식
var square = function(number) {
return number * number;
};
// 기명 함수 표현식(named function expression)
var foo = function multiply(a, b) {
return a * b;
};
// 익명 함수 표현식(anonymous function expression)
var bar = function(a, b) {
return a * b;
};
console.log(foo(10, 5)); // 50
console.log(multiply(10, 5)); // Uncaught ReferenceError: multiply is not defined
var foo = function(a, b) {
return a * b;
};
var bar = foo;
// 변수 bar와 변수 foo는 동일한 익명 함수의 참조값을 갖는다.
console.log(foo(10, 10)); // 100
console.log(bar(10, 10)); // 100
// 사용자가 작성한 함수 선언문
function square(number) {
return number * number;
}
// JS엔진이 해석하는 함수 선언문
var square = function square(number) {
return number * number;
};
var square = new Function('number', 'return number * number');
console.log(square(10)); // 100
var res = square(5);
function square(number) {
return number * number;
}
var res = square(5); // TypeError: square is not a function
var square = function(number) {
return number * number;
}
함수 표현식의 경우 함수 호이스팅이 아니라 변수 호이스팅이 발생하기 때문에 타입에러가 발생한다.
변수 호이스팅은 변수 생성 및 초기화와 할당이 분리되어 진행된다.
호이스팅된 변수는 undefined로 초기화 되고, 실제값의 할당은 할당문에서 이루어진다.
함수표현식은 함수선언문과는 다르게 스크립트 로딩 시점에 변수객체(VO)에 함수를 할당하지 않고, runtime에 해석되고 실행되므로 이 두가지를 구분하는 것은 중요하다.
이와 같은 문제때문에 함수표현식 만을 사용할것을 권고하고있다.
함수 호이스팅이 함수 호출전 반드시 함수를 선언하여야한다. 라는 규칙을 무시하므로 코드의 구조를 엉성하게 만들 수 있다고 지적한다.
또한 함수선언문 으로 함수를 정의하면 VO에 너무많은 변수객체를 저장하게 되면 애플리케이션의 응답속도가 현저히 떨어지므로 주의해야 한다.
// 1. 무명의 리터럴로 표현이 가능하다.
// 2. 변수나 자료 구조에 저장할 수 있다.
var increase = function (num) {
return ++num;
};
var decrease = function (num) {
return --num;
};
var predicates = { increase, decrease };
// 3. 함수의 매개변수에 전달할 수 있다.
// 4. 반환값으로 사용할 수 있다.
function makeCounter(predicate) {
var num = 0;
return function () {
num = predicate(num);
return num;
};
}
var increaser = makeCounter(predicates.increase);
console.log(increaser()); // 1
console.log(increaser()); // 2
var decreaser = makeCounter(predicates.decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2
var foo = function (p1, p2) {
console.log(p1, p2);
};
foo(1); // 1 undefined
function foo(primitive) {
primitive += 1;
return primitive;
}
var x = 0;
console.log(foo(x)); // 1
console.log(x); // 0
function changeVal(primitive, obj) {
primitive += 100;
obj.name = 'Kim';
obj.gender = 'female';
}
var num = 100;
var obj = {
name: 'Lee',
gender: 'male'
};
console.log(num); // 100
console.log(obj); // Object {name: 'Lee', gender: 'male'}
changeVal(num, obj);
console.log(num); // 100
console.log(obj); // Object {name: 'Kim', gender: 'female'}
function calculateArea(width, height) {
var area = width * height;
return area; // 단일 값의 반환
}
console.log(calculateArea(3, 5)); // 15
console.log(calculateArea(8, 5)); // 40
function getSize(width, height, depth) {
var area = width * height;
var volume = width * height * depth;
return [area, volume]; // 복수 값의 반환
}
console.log('area is ' + getSize(3, 2, 3)[0]); // area is 6
console.log('volume is ' + getSize(3, 2, 3)[1]); // volume is 18
function square(number) {
return number * number;
}
square.x = 10;
square.y = 20;
console.log(square.x, square.y); // 10 20
function multiply(x, y) {
console.log(arguments);
return x * y;
}
multiply(); // {}
multiply(1); // { '0': 1 }
multiply(1, 2); // { '0': 1, '1': 2 }
multiply(1, 2, 3); // { '0': 1, '1': 2, '2': 3 }
// arguments 객체는 매개변수 갯수가 확정되지 않은 가변 인자 함수를 구현할 때 유용하게 사용된다.
function sum() {
var res = 0;
for (var i = 0; i < arguments.length; i++) {
res += arguments[i];
}
return res;
}
console.log(sum()); // 0
console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3)); // 6
function sum() {
if (!arguments.length) return 0;
// arguments 객체를 배열로 변환
var array = Array.prototype.slice.call(arguments);
return array.reduce(function (pre, cur) {
return pre + cur;
});
}
// ES6
function sum(...args) {
if (!args.length) return 0;
return args.reduce((pre, cur) => pre + cur);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
function foo(func) {
var res = func();
return res;
}
function bar() {
return 'caller : ' + bar.caller;
}
console.log(foo(bar)); // caller : function foo(func) {...}
console.log(bar()); // null (browser에서의 실행 결과)
function foo() {}
console.log(foo.length); // 0
function bar(x) {
return x;
}
console.log(bar.length); // 1
function baz(x, y) {
return x * y;
}
console.log(baz.length); // 2
// 기명 함수 표현식(named function expression)
var namedFunc = function multiply(a, b) {
return a * b;
};
// 익명 함수 표현식(anonymous function expression)
var anonymousFunc = function(a, b) {
return a * b;
};
console.log(namedFunc.name); // multiply
console.log(anonymousFunc.name); // ''
__proto__
접근자 프로퍼티__proto__
프로퍼티는 [[Prototype]] 내부 슬롯이 가르키는 프로토타입 객체에 접근하기 위해 사용하는 접근자 프로퍼티 이다.__proto__
접근자 프로퍼티를 통해 간접적으로 프로토타입 객체에 접근할 수 있다.// __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입 객체에 접근할 수 있다.
// 객체 리터럴로 셍성한 객체의 프로토타입 객체는 Object.prototype이다.
console.log({}.__proto__ === Object.prototype); // true
__proto__
프로퍼티는 객체가 직접소유하는 프로퍼티가 아니라 모든 객체의 프로토타입 객체인 Object.prototype 객체의 프로퍼티이다.__proto__
접근자 프로퍼티를 사용할 수 있다.// 객체는 __proto__ 프로퍼티를 소유하지 않는다.
console.log(Object.getOwnPropertyDescriptor({}, '__proto__'));
// undefined
// __proto__ 프로퍼티는 모든 객체의 프로토타입 객체인 Object.prototype의 접근자 프로퍼티이다.
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// {get: ƒ, set: ƒ, enumerable: false, configurable: true}
// 모든 객체는 Object.prototype의 접근자 프로퍼티 __proto__를 상속받아 사용할 수 있다.
console.log({}.__proto__ === Object.prototype); // true
__proto__
접근자 프로퍼티를 통해 프로토타입 객체에 접근할 수 있다.// 함수 객체의 프로토타입 객체는 Function.prototype이다.
console.log((function() {}).__proto__ === Function.prototype); // true
// 함수 객체는 prototype 프로퍼티를 소유한다.
console.log(Object.getOwnPropertyDescriptor(function() {}, 'prototype'));
// {value: {…}, writable: true, enumerable: false, configurable: false}
// 일반 객체는 prototype 프로퍼티를 소유하지 않는다.
console.log(Object.getOwnPropertyDescriptor({}, 'prototype'));
// undefined
// 기명 즉시 실행 함수(named immediately-invoked function expression)
(function myFunction() {
var a = 3;
var b = 5;
return a * b;
}());
// 익명 즉시 실행 함수(immediately-invoked function expression)
(function () {
var a = 3;
var b = 5;
return a * b;
}());
// SyntaxError: Unexpected token (
// 함수선언문은 자바스크립트 엔진에 의해 함수 몸체를 닫는 중괄호 뒤에 ;가 자동 추가된다.
function () {
// ...
}(); // => };();
// 따라서 즉시 실행 함수는 소괄호로 감싸준다.
(function () {
// ...
}());
(function () {
// ...
})();
(function () {
var foo = 1;
console.log(foo);
}());
var foo = 100;
console.log(foo);
function parent(param) {
var parentVar = param;
function child() {
var childVar = 'lee';
console.log(parentVar + ' ' + childVar); // Hello lee
}
child();
console.log(parentVar + ' ' + childVar);
// Uncaught ReferenceError: childVar is not defined
}
parent('Hello');
function sayHello(name){
var text = 'Hello ' + name;
var logHello = function(){ console.log(text); }
logHello();
}
sayHello('lee'); // Hello lee
logHello('lee'); // logHello is not defined
// 피보나치 수열
// 피보나치 수는 0과 1로 시작하며, 다음 피보나치 수는 바로 앞의 두 피보나치 수의 합이 된다.
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, ...
function fibonacci(n) {
if (n < 2) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(0)); // 0
console.log(fibonacci(1)); // 1
console.log(fibonacci(2)); // 1
console.log(fibonacci(3)); // 2
console.log(fibonacci(4)); // 3
console.log(fibonacci(5)); // 5
console.log(fibonacci(6)); // 8
// 팩토리얼
// 팩토리얼(계승)은 1부터 자신까지의 모든 양의 정수의 곱이다.
// n! = 1 * 2 * ... * (n-1) * n
function factorial(n) {
if (n < 2) return 1;
return factorial(n - 1) * n;
}
console.log(factorial(0)); // 1
console.log(factorial(1)); // 1
console.log(factorial(2)); // 2
console.log(factorial(3)); // 6
console.log(factorial(4)); // 24
console.log(factorial(5)); // 120
console.log(factorial(6)); // 720
<!DOCTYPE html>
<html>
<body>
<button id="myButton">Click me</button>
<script>
var button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log('button clicked!');
});
</script>
</body>
</html>
setTimeout(function () {
console.log('1초 후 출력된다.');
}, 1000);
function doSomething() {
var name = 'Lee';
setTimeout(function () {
console.log('My name is ' + name);
}, 100);
}
doSomething(); // My name is Lee