Functions
함수 parameter / argument는 2개 이하
함수 테스팅을 쉽게 만들어 주기 때문
3개 이상인 경우: 통합하기
higher-level object의 경우 1개로 충분함
객체를 생성하고 활용하기
- 적은 boilerplate으로도 객체를 만들기 쉬우므로, argument가 많이 필요한 경우 객체를 생성해서 활용하기
boilerplate
: 변경 없이 계속 재사용할 수 있는 코드, 프로그램Destructuring
구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.
function signature
(argument, return type) 등을 통해 어떤 값이 전달되고 이용되는지 알 수 있음- simulate
named parameters
named parameters : function calls that clearly state the name of each parameter within the function call
전달된 argument
에 default 값을 복제함, argument로부터 destructure된 object / array는 복제되지 않음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// bad
function createMenu(title, body, buttonText, cancellable) {
// ...
}
createMenu("Foo", "Bar", "Baz", true);
// good
function createMenu({ title, body, buttonText, cancellable }) {
// ...
}
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
});
하나의 함수는 하나의 행동만
1 | // bad |
- 함수명은 명시적으로 action을 정의하기
1 | // bad |
- (2)와 비슷한 맥락으로, 재사용 가능하고 테스트가 용이할 수 있도록 하나의 함수는 one level of abstraction을 담당하도록 한다.
❓(2)와 어떤 차이가 있는지?
1 | // bad |
중복된 코드는 삭제하기
비슷한 일을 하는 함수들이 사소한 차이로 개별적으로 존재하는 경우
👉
추상화
를 통해 하나의 함수/ 모듈/ 클래스를 사용하여 사소한 차이점을 (argument 등으로) 다루기 : 한 곳만 수정해도 다른 코드에 반영할 수 있음e.g. JAVA의 class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53// bad
function showDeveloperList(developers) {
developers.forEach(developers => {
const expectedSalary = developer.calculateExpectedSalary();
const experience = developer.getExperience();
const githubLink = developer.getGithubLink(); // 👈 difference
const data = {
expectedSalary,
experience,
githubLink
};
render(data);
});
}
function showManagerList(managers) {
managers.forEach(manager => {
const expectedSalary = manager.calculateExpectedSalary();
const experience = manager.getExperience();
const portfolio = manager.getMBAProjects(); // 👈 difference
const data = {
expectedSalary,
experience,
portfolio
};
render(data);
});
}
// good
function showEmployeeList(employees) {
employees.forEach((employee) => {
const expectedSalary = employee.calculateExpectedSalary();
const experience = employee.getExperience();
let portfolio = employee.getGithubLink();
if (employee.type === 'manager') {
portfolio = employee.getMBAProjects();
}
const data = {
expectedSalary,
experience,
portfolio
};
render(data);
});
}Object.assign
으로 default object 만들기
1 | // bad |
- function parameter에 flags 전달하지 않기
flags
는 그 자체로 하나 이상의 기능을 하는 것을 의미하므로, 단일 기능을 하는 함수로 나누기!
플래그(flags)
정규 표현식을 생성할 때 플래그를 사용하여 기본 검색 설정을 변경할 수 있습니다.
이렇게 설정된 플래그는 나중에 추가되거나 삭제될 수 없습니다.
플래그(flag) 설명 i 검색 패턴을 비교할 때 대소문자를 구분하지 않도록 설정함. g 검색 패턴을 비교할 때 일치하는 모든 부분을 선택하도록 설정함. m 검색 패턴을 비교할 때 여러 줄의 입력 문자열을 그 상태 그대로 여러 줄로 비교하도록 설정함. y 대상 문자열의 현재 위치부터 비교를 시작하도록 설정함.
1 | // bad |
Side Effect
함수가
take a value in and return another value / values
외의 action을 할 경우 side effect가 발생함e.g. writing to a file, modifying some global variable, etc.
- side effect를 발생시키는 함수를 정의할 경우,
centralize where you are doing this
(하나의 함수로 통일할 것!)- pitfall (uncatchable error) 을 피하기 위함
- e.g. sharing state between objects without any elucidation / saving, using mutable data types that can be written to anything 👉
TypeScript
이용하기, not centralizing where your side effects occur
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// bad
// Global variable referenced by following function.
// If we had another function that used this name, now it'd be an array and it could break the logic it originally had.
let name = "Ryan McDermott";
function splitIntoFirstAndLastName() {
name = name.split(" ");
}
splitIntoFirstAndLastName();
console.log(name); // ['Ryan', 'McDermott'];
// good
function splitIntoFirstAndLastName(name) {
return name.split(" ");
}
const name = "Ryan McDermott";
const newName = splitIntoFirstAndLastName(name);
console.log(name); // 'Ryan McDermott';
console.log(newName); // ['Ryan', 'McDermott'];- Handling changeable (mutable) values / data by
cloning
- input object를 직접적으로 mutate하는 경우는 많지 않으므로,
clone - edit - return
하기 - improve performance efficiency using great libraries
- input object를 직접적으로 mutate하는 경우는 많지 않으므로,
1
2
3
4
5
6
7
8
9
10
11// bad
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
// good
const addItemToCart = (cart, item) => {
// new array
return [...cart, { item, date : Date.now() }];
}- side effect를 발생시키는 함수를 정의할 경우,
global function 사용하지 않기
- 내장된 library와 충돌할 수 있음
- 똑같은 이름의 함수가 다른 action
- 다른 이름의 함수가 같은 action
- error handling, exception 처리 없이는 해당 API를 사용할 때 문제 발생
👉
inheritance
이용하기!- 내장된 library와 충돌할 수 있음
1 | // bad |
imperative 보다 favor(functional) programming 하기
Imperative programming : writing your program as a series of instructions (statements) that can actively modify memory (variables, arrays)
- focuses on how : express the logic of your program based on how the computer would execute it
Functional programming : writing your program in terms of functions and other mathematical structures
- A function is just a rule that maps input elements to output
- concentrates on the what : trying to let you specify the logic of your program as close to actual logic as possible
- more expressive : writing less code
- safer : more bugs are prevented by the language ahead of time
- side-effects are controlled
1 | const programmerOutput = [ |
- 조건문(Conditionals) Encapsulation
Encapsulation
bundling data and methods that work on that data within one unit
- hide the internal representation, or state, of an object from the outside
- e.g., a class in Java
1 | // bad |
- 부정조건문 피하기
1 | // bad |
- 조건문 피하기
- 조건문 자체가 함수가 하나 이상의 일을 하고 있음을 의미함
👉 각 case에 해당되는 함수 개별적으로 만들기
1 | // bad |
- Type-checking 피하기
consistent APIs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// bad
function travelToTexas(vehicle) {
if (vehicle instanceof Bicycle) {
vehicle.pedal(this.currentLocation, new Location('texas'));
} else if (vehicle instanceof Car) {
vehicle.drive(this.currentLocation, new Location('texas'));
}
}
// good
// case 별로 move function을 달리 하는 것이 아니라,
// `move`로 동일하게 생성
function travelToTexas(vehicle) {
vehicle.move(this.currentLocation, new Location('texas'));
}TypeScript
- basic primitive를 이용해서 polymorphism 속성을 활용할 수 없을 때
- provides you with static typing on top of standard JavaScript syntax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// bad
function combine(val1, val2) {
if (typeof val1 === 'number' && typeof val2 === 'number' ||
typeof val1 === 'string' && typeof val2 === 'string') {
return val1 + val2;
}
throw new Error('Must be of type String or Number');
}
// good
// ※ with Typescript
function combine(val1, val2) {
return val1 + val2;
}
over-optimising 피하기
- There are good resources 를 통해 optimisation is lacking 부분만 체크하고 고치기
1
2
3
4
5
6
7
8
9
10
11
12
13// bad
// On old browsers, each iteration with "uncached" `list.length` would be costly
// (need to recomputate every time it runs for loop)
// because of `list.length` recomputation. In modern browsers, this is optimized.
for (let i = 0, len = list.length; i < len; i++) {
// ...
}
// good
for (let i = 0; i < list.length; i++) {
// ...
}Dead Code 지우기
- If it’s not being called, get rid of it!
- keep it in your version history if you still need it
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// bad
function oldRequestModule(url) {
// ...
}
function newRequestModule(url) {
// ...
}
const req = newRequestModule;
inventoryTracker('apples', req, 'www.inventory-awesome.io');
// good
function newRequestModule(url) {
// ...
}
const req = newRequestModule;
inventoryTracker('apples', req, 'www.inventory-awesome.io');- If it’s not being called, get rid of it!