1️⃣ 명시적 변환, 암시적 변환, Nominal, 구조화, 덕 타이핑
2️⃣ 고차함수
3️⃣ 컬렉션과 생성기
4️⃣ 순수함수, 부수효과, 상태변이
5️⃣ 닫기/폐쇄 (Closure)
명시적 형변환
암시적 형변환
+
: 문자열이 우선되므로, 숫자 + 문자
는 문자열로 변환된다.그 외
: 숫자형이 우선되므로, 숫자 - / * % 문자
는 숫자로 변환된다.==
: 숫자와 문자열을 비교할 때 느슨한 비교를 통해 타입을 고려하지 않고 값이 같으면 true로 반환한다.JavaSciript의 타이핑
명목적 타이핑(Nominal Typing)
int a = 3;
a = 's' // Error
int
와 같이 선언하고자 하는 변수에 타입을 지정함으로서 에러를 방지할 수 있다.
C나 Java, Python에서 사용되고 있다.
덕 타이핑(Duck Typing)
타입을 미리 정하는 게 아닌, 객체의 메소드 존재 여부 등으로 객체의 타입을 결정해 사용하는 방식이다.
JavaScript가 이 방식을 사용한다.
덕 타이핑이라는 이름의 유래는 ‘덕 테스트(Duck Test)’에서 유래가 됐다.
만약 어떤 새가 오리처럼 걷고, 헤엄치고, 꽥꽥거리는 소리를 낸다면 나는 그 새를 오리라고 부를 것이다.
class Duck {
quack() {
console.log('꽥!')
}
feathers() {
console.log('깃털은 검정색과 흰색')
}
}
class Human {
quack() {
console.log('사람인데요? 꽥!')
}
feathers() {
console.log('사람이라 깃털은 없어요. 하지만 털은 있습니다.')
}
}
function inTheForest(duck) {
duck.quack()
duck.feathers()
}
inTheForest(new Duck())
inTheForest(new Human())
위의 함수 inTheForest
는 duck
이라는 매개변수, 파라미터를 가진다.
함수의 안에는 duck
의 메소드인 quack()
와 feathers()
가 지정되어있다.
함수 이전에 우리는 인간이라는 Human
과 오리라는 Duck
을 class
로 선언한 뒤, inTherForest()
를 이용해 결과를 적용해봤다.
그 결과 Human
이든 Duck
이든 class
안에 quack()
와 features()
메소드가 있으므로 둘 다 inTheForest()
의 값을 반환한다.
duck
이라는 파라미터가 들어올 때에는 값의 데이터 타입을 검사하지 않는다.
구조적 타이핑(Structural Typing)
interface Vector2D {
x: number;
y: number;
}
function calculateLength(v: Vector2D) {
return v.x + v.y;
}
interface NamedVector {
name: string;
x: number;
y: number;
}
const v: NamedVector = { x: 3, y: 4, name: 'Zee' };
calculateLength(v) // 7
위의 코드에서 함수 calculateLength
는 약속을 정의내린 interface
, Vector2D
의 내용대로 매개변수의 타입을 체크한다.
그런데 여기서 NamedVector
라는 새로운 interface
로 약속을 정의내린 걸 가지고 함수 calculateLength
에 사용하려고 한다.
NamedVector
는 Vector2D
와 내용이 다르므로 함수가 에러를 내뱉을 수 있다고 생각할 수 있으나, NamedVector
는 Vertor2D
의 구조에서 name
key가 추가된 것뿐이다.
따라서 기본적인 Vector2D
의 구조를 갖추고, 거기에 key 하나가 추가된 것이므로 구조적으로 결함이 없다고 판단하여 함수 calculateLength
가 문제 없이 실행된다.
(공부하는 입장에선 아직 이 구조적 타이핑 내용이 와닿지 않는다. 추후 타입스크립트를 공부하고 재정리해보려고 한다.)
이전에 학습했던 내용이 있어 해당 내용을 발췌했다.
고차함수(Higher Order Function)
이전의 프로토타입 체인 등을 공부했던 내용을 떠올려보면 JavaScript에서의 함수는 객체로 받고 있다는 것을 알 수 있을 것이다.
const message = () => {
console.log('함수는 객체라서, 이렇게 변수에 할당할 수 있다.')
}
function example(message) {
console.log('변수에 할당할 수 있다보니, 함수의 인자로도 전달할 수 있다.')
return message;
// 그리고 함수의 반환값으로 함수를 전달할 수도 있다.
}
위의 내용을 콘솔창에 입력하면 아래와 같이 결과를 볼 수 있다.
콜백 함수(Callback Function)
고차 함수의 형태 중에선 ‘다른 함수의 인자’로 전달되는 함수가 있는데, 이를 콜백 함수라고 부른다.
const button = document.querySelector('#btn');
button.addEventHandler('click', sayHello());
function sayHello() {
console.log("안녕하세요!")
}
위의 코드에서 sayHello()
라는 함수는 button
이라는 문서 객체 내에 addEventHandler
라는 메소드(함수)를 통해 인자로 보내진다.
이 인자는 버튼을 클릭하기 전까지는 동작하지 않으나, 버튼을 클릭하는 이벤트가 작동될 때, 이벤트 호출을 받아와 인자에 있는 sayHello()
함수를 반환하여 내용을 작동시키게 한다.
즉, 어떤 이벤트나 작업이 이루어질 때 호출되여 작동한다는 의미로서 답신의 의미인 ‘Callback’을 담아 ‘콜백 함수’라고 불리게 된다.
커리 함수(Curry Function)
const curryExample = () => {
return () => {
console.log("커리 함수입니다!");
}
};
curryExample;
// function curryExample() {
// return () => {
// console.log("커리 함수입니다!");
// }
// }
// 변수의 내용인 함수 내용 자체를 가져온다.
curryExample();
// () => {
// return console.log("커리 함수입니다!");
// }
// 함수를 실행하면 curryExample 함수가 반환하는 함수의 내용을 가져온다.
위와 같은 형태처럼 외부 함수를 실행하면 return값으로 내부의 함수를 반환하는 형태를 가진다. (이러한 형태를 클로저라고 부르는데 해당 내용은 추후에 다룰 것이다.)
이런 경우, 반환 값으로 받고 있는 내부에 있는 함수를 실행하려면 어떻게 해야할까? 바로 아래와 같이 실행하면 된다.
curryExample()();
// 커리 함수입니다!
앞서 변수 curryExample
를 받아오면 함수의 내용을 반환한다.
함수 표현식으로 만들었으니, 이 변수를 함수로서 호출하면 그 함수의 실행 결과를 반환한다.
내부 함수의 값을 반환하려면, 결국 함수 curryExample
함수의 실행 결과로서 반환된 함수를 실행해야 하는 건데 이 방식은 위의 내용처럼 이어서 호출하는 것으로 값을 받아올 수 있게 된다.
위의 내용을 응용하면 이런 식으로도 표현할 수 있다.
const curryExample = () => {
return () => {
console.log("커리 함수입니다!");
}
};
const ex1 = curryExample();
console.log(ex1);
console.log(ex1());
JavaScript의 함수는 이런 커리 함수와 콜백 함수를 사용하지 않을 수도 있고, 단독적으로 쓰거나 함께 적용할 수도 있다.
배열의 내장 고차 함수