- Updated date 2020.01.09
- ํ์ฌ ์๋ฌธ์ 1c0b20a ๊น์ง ๋ฐ์๋์ด ์์ต๋๋ค.
- ์๊ฐ(Introduction)
- ๋ณ์(Variables)
- ํจ์(Functions)
- ๊ฐ์ฒด์ ์๋ฃ๊ตฌ์กฐ(Objects and Data Structures)
- ํด๋์ค(Classes)
- SOLID
- ํ ์คํธ(Testing)
- ๋์์ฑ(Concurrency)
- ์๋ฌ ์ฒ๋ฆฌ(Error Handling)
- ํฌ๋งทํ (Formatting)
- ์ฃผ์(Comments)
- ๋ฒ์ญ(Translation)
์ด ๊ธ์ ์ํํธ์จ์ด ๋ฐฉ๋ฒ๋ก ์ ๊ดํ ์ฑ ๋ค ์ค Robert C. Martin's์ ์ฑ ์ธ Clean Code์ ์๋ ๋ด์ฉ์ JavaScript ์ธ์ด์ ์ ์ฉ์์ผ ์ ์ ๊ธ ์ ๋๋ค. ์ด ๊ธ์ ๋จ์ํ Style Guide๊ฐ ์๋๋ผ JavaScript๋ก ์ฝ๋๋ฅผ ์์ฑํ ๋ ์ฝ๊ธฐ ์ฝ๊ณ , ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉฐ ๋ฆฌํฉํ ๋ง ๊ฐ๋ฅํ๊ฒ๋ ์์ฑํ๋๋ก ๋์์ค๋๋ค.
์ฌ๊ธฐ ์๋ ๋ชจ๋ ์์น์ด ์๊ฒฉํ ์ง์ผ์ ธ์ผํ๋ ๊ฒ์ ์๋๋ฉฐ, ๋ณดํธ์ ์ผ๋ก ํต์ฉ๋๋ ์์น์ ์๋๋๋ค. ์ด๊ฒ๋ค์ ์ง์นจ์ผ ๋ฟ์ด๋ฉฐ Clean Code์ ์ ์๊ฐ ์๋
๊ฐ ๊ฒฝํํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ ๋ฆฌํ ๊ฒ์
๋๋ค.
์ํํธ์จ์ด ์์ง๋์ด๋ง ์ญ์ฌ๋ 50๋ ์ ์กฐ๊ธ ๋๊ฒผ์ง๋ง ์ฐ๋ฆฌ๋ ์์ง๋ ๋ง์ ๊ฒ๋ค์ ๋ฐฐ์ฐ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ํํธ์จ์ด ์ํคํ ์ณ๊ฐ ๊ฑด์ถ์ค๊ณ ๋งํผ์ด๋ ์ค๋๋์์ ๋ ์ฐ๋ฆฌ๋ ์๋ ๊ท์น๋ค๋ณด๋ค ๋ ์๊ฒฉํ ๊ท์น๋ค์ ๋ฐ๋ผ์ผ ํ ์ง๋ ๋ชจ๋ฆ ๋๋ค. ํ์ง๋ง ์ง๊ธ ๋น์ฅ์ ์ด ๊ฐ์ด๋ ๋ผ์ธ์ ๋น์ ๊ณผ ๋น์ ํ์ด ์์ฑํ๋ JavaScript ์ฝ๋์ ํ์ง์ ํ๊ฐํ๋ ๊ธฐ์ค์ผ๋ก ์ผ์ผ์ธ์.
ํ๊ฐ์ง ๋ ๋ง๋ถ์ด์๋ฉด, ์ด ์์น๋ค์ ์๊ฒ๋๋คํด์ ๋น์ฅ ๋ ๋์ ๊ฐ๋ฐ์๊ฐ ๋๋ ๊ฒ์ ์๋๋ฉฐ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์ค์๋ฅผ ํ์ง ์๊ฒ ํด์ฃผ๋ ๊ฒ์ ์๋๋๋ค. ํ๋ฅญํ ๋์๊ธฐ๋ค์ด ์ฒ์์ ๋ง๋ํ ์ ํ ๋ถํฐ ์์ํ๋ฏ์ด ๋ชจ๋ ์ฝ๋๋ค์ ์ฒ์๋ถํฐ ์๋ฒฝํ ์ ์์ต๋๋ค. ํ์ง๋ง ๋น์ ์ ํ์๋ค๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ๋ฆฌ๋ทฐํ๋ฉฐ ์ ์ ์๋ฒฝํ๊ฒ ๋ง๋ค์ด๊ฐ์ผ ํฉ๋๋ค. ๋น์ ์ด ์ฒ์ ์์ฑํ ์ฝ๋๋ฅผ ๊ณ ์น ๋ ์ ๋๋ก ์์ ์ ์งํํ์ง ๋ง์ธ์. ๋์ ์ฝ๋๋ฅผ ๋ถ์๊ณ ๋ ๋์ ์ฝ๋๋ฅผ ๋ง๋์ธ์!
์์ข์ ์:
const yyyymmdstr = moment().format('YYYY/MM/DD');์ข์ ์:
const currentDate = moment().format('YYYY/MM/DD');์์ข์ ์:
getUserInfo();
getClientData();
getCustomerRecord();์ข์ ์:
getUser();์ฐ๋ฆฌ๋ ์์ฑํ ์ฝ๋๋ณด๋ค ์ฝ์ ์ฝ๋๊ฐ ๋ ๋ง์ต๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ์ฝ๊ธฐ ์ฝ๊ณ ๊ฒ์ ๊ฐ๋ฅํ๊ฒ ์์ฑํด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ฌ๋ฌ๋ถ์ ์ฝ๋๋ฅผ ์ดํดํ๋ ค๊ณ ํ๋ ์ฌ๋๋ค์๊ฒ ํฐ ์ด๋ ค์์ ์ค๋๋ค. ๊ฒ์๊ฐ๋ฅํ ์ด๋ฆ์ผ๋ก ๋ง๋์ธ์. buddy.js ๊ทธ๋ฆฌ๊ณ ESLint ์ ๊ฐ์ ๋๊ตฌ๋ค์ด ์ด๋ฆ์ด ์ ํด์ ธ์์ง ์์ ์์๋ค์ ๋ฐ๊ฒฌํ๊ณ ๊ณ ์น ์ ์๊ฒ ๋์์ค๋๋ค.
์์ข์ ์:
// ๋์ฒด 86400000 ๋ฌด์์ ์๋ฏธํ๋ ๊ฑธ๊น์?
setTimeout(blastOff, 86400000);์ข์ ์
// ๋๋ฌธ์๋ก `const` ์ ์ญ ๋ณ์๋ฅผ ์ ์ธํ์ธ์
const MILLISECONDS_IN_A_DAY = 86400000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);์์ข์ ์:
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);์ข์ ์:
const address = 'One Infinite Loop, Cupertino 95014';
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);๋ช ์์ ์ธ ๊ฒ์ด ์์์ ์ธ ๊ฒ๋ณด๋ค ์ข์ต๋๋ค.
์์ข์ ์:
const locations = ['์์ธ', '์ธ์ฒ', '์์'];
locations.forEach(l => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
// ์ ๊น, `l`์ ๋ ๋ญ๊น์?
dispatch(l);
});์ข์ ์:
const locations = ['์์ธ', '์ธ์ฒ', '์์'];
locations.forEach(location => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
dispatch(location);
});์์ข์ ์:
const Car = {
carMake: 'BMW',
carModel: 'M3',
carColor: 'ํ๋์'
};
function paintCar(car) {
car.carColor = '๋นจ๊ฐ์';
}์ข์ ์:
const Car = {
make: 'BMW',
model: 'M3',
color: 'ํ๋์'
};
function paintCar(car) {
car.color = '๋นจ๊ฐ์';
}๊ธฐ๋ณธ ๋งค๊ฐ๋ณ์๋ ์ข
์ข
short circuiting ํธ๋ฆญ๋ณด๋ค ๊น๋ํฉ๋๋ค. ๊ธฐ๋ณธ ๋งค๊ฐ๋ณ์๋ ๋งค๊ฐ๋ณ์๊ฐ undefined์ผ๋๋ง
์ ์ฉ๋ฉ๋๋ค. '', "", false, null, 0, NaN ๊ฐ์ falsyํ ๊ฐ๋ค์ ๊ธฐ๋ณธ ๋งค๊ฐ๋ณ์๊ฐ ์ ์ฉ๋์ง ์์ต๋๋ค.
์์ข์ ์:
function createMicrobrewery(name) {
const breweryName = name || 'Hipster Brew Co.';
// ...
}์ข์ ์:
function createMicrobrewery(name = 'Hipster Brew Co.') {
// ...
}๋งค๊ฐ๋ณ์์ ๊ฐ์๋ฅผ ์ ํ ํ๋ ๊ฒ์ ํจ์ ํ ์คํ ์ ์ฝ๊ฒ ๋ง๋ค์ด ์ฃผ๊ธฐ ๋๋ฌธ์ ์ค์ํฉ๋๋ค. ๋ง์ฝ ๋งค๊ฐ๋ณ์๊ฐ 3๊ฐ ์ด์์ผ ๊ฒฝ์ฐ์ ํ ์คํธ ํด์ผํ๋ ๊ฒฝ์ฐ์ ์๊ฐ ๋ง์์ง๊ณ ๊ฐ๊ธฐ ๋ค๋ฅธ ์ธ์๋ค๋ก ์ฌ๋ฌ ์ฌ๋ก๋ค์ ํ ์คํธ ํด์ผํฉ๋๋ค.
1๊ฐ๋ 2๊ฐ์ ์ธ์๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ด ๊ฐ์ฅ ์ด์์ ์ธ ์ผ์ด์ค์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ 3๊ฐ์ ์ธ์๋ ๊ฐ๋ฅํ ํผํด์ผํฉ๋๋ค. ๊ทธ๊ฒ๋ณด๋ค ๋ ๋ง๋ค๋ฉด ํตํฉ๋์ด์ผํฉ๋๋ค. ๋ง์ฝ ๋น์ ์ด 2๊ฐ ์ด์์ ์ธ์๋ฅผ ๊ฐ์ง ํจ์๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๊ทธ ํจ์์๊ฒ ๋๋ฌด ๋ง์ ์ญํ ์ ํ๊ฒ ๋ง๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ๋ผ๋ฉด ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์์ ๊ฐ์ฒด๋ 1๊ฐ์ ์ธ์๋ง์ผ๋ก ์ถฉ๋ถํฉ๋๋ค.
JavaScript๋ฅผ ์ฌ์ฉํ ๋ ๋ง์ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์์ด ๋ฐ๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๋น์ ์ด ๋ง์ฝ ๋ง์ ์ธ์๋ค์ ์ฌ์ฉํด์ผ ํ๋ค๋ฉด ๊ฐ์ฒด๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค.
ํจ์๊ฐ ๊ธฐ๋ํ๋ ์์ฑ์ ์ข๋ ๋ช ํํ ํ๊ธฐ ์ํด์ es6์ ๋น๊ตฌ์กฐํ(destructuring) ๊ตฌ๋ฌธ์ ์ฌ์ฉํ ์ ์๊ณ ์ด ๊ตฌ๋ฌธ์๋ ๋ช๊ฐ์ง ์ฅ์ ์ด ์์ต๋๋ค.
- ์ด๋ค ์ฌ๋์ด ๊ทธ ํจ์์ ์๊ทธ๋์ณ(์ธ์์ ํ์ , ๋ฐํ๋๋ ๊ฐ์ ํ์ ๋ฑ)๋ฅผ ๋ณผ ๋ ์ด๋ค ์์ฑ์ด ์ฌ์ฉ๋๋์ง ์ฆ์ ์ ์ ์์ต๋๋ค.
- ๋ํ ๋น๊ตฌ์กฐํ๋ ํจ์์ ์ ๋ฌ๋ ์ธ์ ๊ฐ์ฒด์ ์ง์ ๋ ๊ธฐ๋ณธํ์ ๊ฐ์ ๋ณต์ ํ๋ฉฐ ์ด๋ ์ฌ์ด๋์ดํํธ๊ฐ ์ผ์ด๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค. ์ฐธ๊ณ ๋ก ์ธ์ ๊ฐ์ฒด๋ก๋ถํฐ ๋น๊ตฌ์กฐํ๋ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ๋ณต์ ๋์ง ์์ต๋๋ค.
- Linter๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ฉํ์ง์๋ ์ธ์์ ๋ํด ๊ฒฝ๊ณ ํด์ฃผ๊ฑฐ๋ ๋น๊ตฌ์กฐํ ์์ด ์ฝ๋๋ฅผ ์งค ์ ์๊ฒ ํ ์ ์์ต๋๋ค.
์์ข์ ์:
function createMenu(title, body, buttonText, cancellable) {
// ...
}์ข์ ์:
function createMenu({ title, body, buttonText, cancellable }) {
// ...
}
createMenu({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
});์ด๊ฒ์ ์ํํธ์จ์ด ์์ง๋์ด๋ง์์ ๊ฐ์ฅ ์ค์ํ ๊ท์น์ ๋๋ค. ํจ์๊ฐ 1๊ฐ ์ด์์ ํ๋์ ํ๋ค๋ฉด ์์ฑํ๋ ๊ฒ๋, ํ ์คํธํ๋ ๊ฒ๋, ์ดํดํ๋ ๊ฒ๋ ์ด๋ ค์์ง๋๋ค. ๋น์ ์ด ํ๋์ ํจ์์ ํ๋์ ํ๋์ ์ ์ํ๋ ๊ฒ์ด ๊ฐ๋ฅํด์ง๋ค๋ฉด ํจ์๋ ์ข ๋ ๊ณ ์น๊ธฐ ์ฌ์์ง๊ณ ์ฝ๋๋ค์ ์ฝ๊ธฐ ์ฌ์์ง ๊ฒ์ ๋๋ค. ๋ง์ ์์น๋ค ์ค ์ด๊ฒ๋ง ์์๊ฐ๋ค ํ๋๋ผ๋ ๋น์ ์ ๋ง์ ๊ฐ๋ฐ์๋ค์ ์์ค ์ ์์ต๋๋ค.
์์ข์ ์:
function emailClients(clients) {
clients.forEach(client => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}์ข์ ์:
function emailClients(clients) {
clients
.filter(isClientActive)
.forEach(email);
}
function isClientActive(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}์์ข์ ์:
function AddToDate(date, month) {
// ...
}
const date = new Date();
// ๋ญ ์ถ๊ฐํ๋ ๊ฑด์ง ์ด๋ฆ๋ง ๋ณด๊ณ ์์๋ด๊ธฐ ํ๋ญ๋๋ค.
AddToDate(date, 1);์ข์ ์:
function AddMonthToDate(date, month) {
// ...
}
const date = new Date();
AddMonthToDate(date, 1);์ถ์ํ๋ ์ด๋ฆ์ด ์ฌ๋ฌ ์๋ฏธ๋ฅผ ๋ดํฌํ๊ณ ์๋ค๋ฉด ๊ทธ ํจ์๋ ๋๋ฌด ๋ง์ ์ผ์ ํ๊ฒ๋ ์ค๊ณ๋ ๊ฒ์ ๋๋ค. ํจ์๋ค์ ๋๋์ด์ ์ฌ์ฌ์ฉ๊ฐ๋ฅํ๊ณ ํ ์คํธํ๊ธฐ ์ฝ๊ฒ ๋ง๋์ธ์.
์์ข์ ์:
function parseBetterJSAlternative(code) {
const REGEXES = [
// ...
];
const statements = code.split(' ');
const tokens = [];
REGEXES.forEach(REGEX => {
statements.forEach(statement => {
// ...
});
});
const ast = [];
tokens.forEach(token => {
// lex...
});
ast.forEach(node => {
// parse...
});
}์ข์ ์:
function tokenize(code) {
const REGEXES = [
// ...
];
const statements = code.split(' ');
const tokens = [];
REGEXES.forEach(REGEX => {
statements.forEach(statement => {
tokens.push( /* ... */ );
});
});
return tokens;
}
function lexer(tokens) {
const ast = [];
tokens.forEach(token => {
ast.push( /* ... */ );
});
return ast;
}
function parseBetterJSAlternative(code) {
const tokens = tokenize(code);
const ast = lexer(tokens);
ast.forEach(node => {
// parse...
});
}์ค๋ณต๋ ์ฝ๋๋ฅผ ์์ฑํ์ง ์๊ธฐ์ํด ์ต์ ์ ๋คํ์ธ์. ์ค๋ณต๋ ์ฝ๋๊ฐ ์๋ค๋ ๊ฒ์ ์ด๋ค ๋ก์ง์ ์์ ํด์ผ ํ ์ผ์ด ์๊ฒผ์ ๋ ์์ ํด์ผํ ์ฝ๋๊ฐ ํ ๊ณณ ์ด์์ด๋ผ๋ ๊ฒ์ ๋ปํฉ๋๋ค.
๋ง์ฝ ๋น์ ์ด ๋ ์คํ ๋์ ์ด์ํ๋ฉด์ ํ ๋งํ ๋ ์ํ, ๋ง๋, ๊ณ ์ถ๊ฐ์ ๊ฒ๋ค์ ์ฌ๊ณ ๊ด๋ฆฌ๋ฅผ ํด์ผํ๋ค๊ณ ์๊ฐํด๋ณด์ธ์. ์ฌ๊ณ ๊ฐ ์ ํ์๋ ์ข ์ด๊ฐ ์ฌ๋ฌ์ฅ ์๋ค๋ฉด ํ ๋งํ ๋ ์ํ์ ์ฌ๊ณ ๊ฐ ๋ณ๋๋์์ ๋ ์ฌ๊ณ ๊ฐ ์ ํ์๋ ๋ชจ๋ ์ข ์ด๋ฅผ ์์ ํด์ผ ํฉ๋๋ค. ๋ง์ฝ ์ฌ๊ณ ๋ฅผ ๊ด๋ฆฌํ๋ ์ข ์ด๊ฐ ํ ์ฅ์ด์๋ค๋ฉด ํ ์ฅ์ ์ฌ๊ณ ๋ชฉ๋ก๋ง ์์ ํ๋ฉด ๋๊ฒ ์ฃ !
์ข ์ข ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด ์ฌ์ํ ๋ช๋ช์ ์ฐจ์ด์ ๋๋ฌธ์ ์ค๋ณต๋ ์ฝ๋๋ฅผ ์์ฑํ ๊ฒฝ์ฐ๊ฐ ์๊ณ ์ด๋ฐ ์ฐจ์ด์ ๋ค์ ๋๋ถ๋ถ ๋๊ฐ์ ์ผ์ ํ๋ ๋ถ๋ฆฌ๋ ํจ์๋ค์ ๊ฐ๋๋ก ๊ฐ์ํฉ๋๋ค. ์ฆ ์ค๋ณต ์ฝ๋๋ฅผ ์ ๊ฑฐํ๋ค๋ ๊ฒ์ ํ๋์ ํจ์ / ๋ชจ๋ / ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ด ์ฌ๋ฌ ๊ฐ์ง ์ฌ์ํ ์ฐจ์ด์ ์ ์ฒ๋ฆฌ ํ ์ ์๋ ์ถ์ํ๋ฅผ ๋ง๋๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ถ์ํ ํ ๋ถ๋ถ์ด ๋จ์์๋ ๊ฒ์ ์ํํ๊ธฐ๋๋ฌธ์ ํด๋์ค ์น์ ์ ์ ์๋ ์ฌ๋ฌ ์์น๋ค์ ๋ฐ๋ผ์ผ ํฉ๋๋ค. ์ ์ถ์ํ ํ์ง ๋ชปํ ์ฝ๋๋ ์ค๋ณต๋ ์ฝ๋๋ณด๋ค ๋์ ์ ์์ผ๋ฏ๋ก ์กฐ์ฌํ์ธ์. ์ฆ ์ถ์ํ๋ฅผ ์ ํ ์ ์๋ค๋ฉด ๊ทธ๋ ๊ฒ ํ๋ผ๋ ๋ง์ ๋๋ค. ์ฝ๋์ ์ค๋ณต์ ํผํ๋ค๋ฉด ์ฌ๋ฌ๋ถ์ด ์ํ ๋ ์ธ์ ๋ ํ ๊ณณ๋ง ์์ ํด๋ ๋ค๋ฅธ ๋ชจ๋ ์ฝ๋์ ๋ฐ์๋๊ฒ ํ ์ ์์ต๋๋ค.
์์ข์ ์:
function showDeveloperList(developers) {
developers.forEach(developers => {
const expectedSalary = developer.calculateExpectedSalary();
const experience = developer.getExperience();
const githubLink = developer.getGithubLink();
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();
const data = {
expectedSalary,
experience,
portfolio
};
render(data);
});
}์ข์ ์:
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);
});
}์์ข์ ์:
const menuConfig = {
title: null,
body: 'Bar',
buttonText: null,
cancellable: true
};
function createMenu(config) {
config.title = config.title || 'Foo';
config.body = config.body || 'Bar';
config.buttonText = config.buttonText || 'Baz';
config.cancellable = config.cancellable !== undefined ? config.cancellable : true;
}
createMenu(menuConfig);์ข์ ์:
const menuConfig = {
title: 'Order',
// ์ ์ ๊ฐ 'body' key์ value๋ฅผ ์ ํ์ง ์์๋ค.
buttonText: 'Send',
cancellable: true
};
function createMenu(config) {
config = Object.assign({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
}, config);
// config๋ ์ด์ ๋ค์๊ณผ ๋์ผํฉ๋๋ค: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// ...
}
createMenu(menuConfig);ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์์ฒด๊ฐ ๊ทธ ํจ์๊ฐ ํ๊ฐ์ง ์ด์์ ์ญํ ์ ํ๊ณ ์๋ค๋ ๊ฒ์ ๋ปํฉ๋๋ค. boolean ๊ธฐ๋ฐ์ผ๋ก ํจ์๊ฐ ์คํ๋๋ ์ฝ๋๊ฐ ๋๋๋ค๋ฉด ํจ์๋ฅผ ๋ถ๋ฆฌํ์ธ์.
์์ข์ ์:
function createFile(name, temp) {
if (temp) {
fs.create(`./temp/${name}`);
} else {
fs.create(name);
}
}์ข์ ์:
function createFile(name) {
fs.create(name);
}
function createTempFile(name) {
createFile(`./temp/${name}`);
}ํจ์๋ ๊ฐ์ ๋ฐ์์ ์ด๋ค ์ผ์ ํ๊ฑฐ๋ ๊ฐ์ ๋ฆฌํดํ ๋ ์ฌ์ด๋ ์ดํฉํธ๋ฅผ ๋ง๋ค์ด๋ ๋๋ค. ์ฌ์ด๋ ์ดํฉํธ๋ ํ์ผ์ ์ฐ์ฌ์ง ์๋ ์๊ณ , ์ ์ญ ๋ณ์๋ฅผ ์์ ํ ์ ์์ผ๋ฉฐ, ์ค์๋ก ๋ชจ๋ ๋์ ๋ค๋ฅธ ์ฌ๋์๊ฒ ๋ณด๋ผ ์๋ ์์ต๋๋ค.
๋น์ ์ ๋๋๋ก ํ๋ก๊ทธ๋จ์์ ์ฌ์ด๋ ์ดํฉํธ๋ฅผ ๋ง๋ค์ด์ผ ํ ๋๊ฐ ์์ต๋๋ค. ์๊น ๋ค์๋ ์๋ค ์ค ํ๋์ธ ํ์ผ์์ฑ์ ํ ๋์ ๊ฐ์ด ๋ง์ด์ฃ . ์ด ๋ ์ฌ๋ฌ๋ถ์ด ํด์ผํ ์ผ์ ํ์ผ ์์ฑ์ ํ๋ ํ ๊ฐ์ ํจ์๋ฅผ ๋ง๋๋ ์ผ ์ ๋๋ค. ํ์ผ์ ์์ฑํ๋ ํจ์๋ ํด๋์ค๊ฐ ์ฌ๋ฌ๊ฐ ์กด์ฌํ๋ฉด ์๋ฉ๋๋ค. ๋ฐ๋์ ํ๋๋ง ์์ด์ผ ํฉ๋๋ค.
์ฆ, ์ด๋ ํ ๊ตฌ์กฐ์ฒด๋ ์์ด ๊ฐ์ฒด ์ฌ์ด์ ์ํ๋ฅผ ๊ณต์ ํ๊ฑฐ๋, ๋ฌด์์ด๋ ์ธ ์ ์๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๋ฐ์ดํฐ ์ ํ์ ์ฌ์ฉํ๊ฑฐ๋, ๊ฐ์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ฒ์ ์ฌ๋ฌ๊ฐ ๋ง๋ค๊ฑฐ๋ํ๋ฉด ์๋ฉ๋๋ค. ์ฌ๋ฌ๋ถ๋ค์ด ์ด๋ฌํ ๊ฒ๋ค์ ์งํค๋ฉฐ ์ฝ๋๋ฅผ ์์ฑํ๋ค๋ฉด ๋๋ถ๋ถ์ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๋ณด๋ค ํ๋ณตํ ์ ์์ต๋๋ค.
์์ข์ ์:
// ์๋ ํจ์์ ์ํด ์ฐธ์กฐ๋๋ ์ ์ญ ๋ณ์์
๋๋ค.
// ์ด ์ ์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ๋ ํ๋์ ํจ์๊ฐ ์๋ค๊ณ ์๊ฐํด๋ณด์ธ์. ์ด์ ์ด ๋ณ์๋ ๋ฐฐ์ด์ด ๋ ๊ฒ์ด๊ณ , ํ๋ก๊ทธ๋จ์ ๋ง๊ฐ๋จ๋ฆฌ๊ฒ ์ฃ .
let name = 'Ryan McDermott';
function splitIntoFirstAndLastName() {
name = name.split(' ');
}
splitIntoFirstAndLastName();
console.log(name); // ['Ryan', 'McDermott'];์ข์ ์:
function splitIntoFirstAndLastName(name) {
return name.split(' ');
}
const name = 'Ryan McDermott';
const newName = splitIntoFirstAndLastName(name);
console.log(name); // 'Ryan McDermott';
console.log(newName); // ['Ryan', 'McDermott'];์๋ฐ์คํฌ๋ฆฝํธ์์๋ ๊ธฐ๋ณธํ์
์๋ฃํ์ ๊ฐ์ ์ ๋ฌํ๊ณ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ์ฐธ์กฐ๋ฅผ ์ ๋ฌํฉ๋๋ค.
๊ฐ์ฒด์ ๋ฐฐ์ด์ธ ๊ฒฝ์ฐ๋ฅผ ํ๋ฒ ์ดํด๋ด
์๋ค. ์ฐ๋ฆฌ๊ฐ ๋ง๋ ํจ์๋ ์ฅ๋ฐ๊ตฌ๋ ๋ฐฐ์ด์ ๋ณํ๋ฅผ ์ฃผ๋ฉฐ
์ด ๋ณํ๋ ๊ตฌ๋งค๋ชฉ๋ก์ ์ด๋ค ์ํ์ ์ถ๊ฐํ๋ ๊ธฐ๋ฅ ๊ฐ์ ๊ฒ์ ๋งํฉ๋๋ค.
๋ง์ฝ ์ฅ๋ฐ๊ตฌ๋ ๋ฐฐ์ด์ ์ฌ์ฉํ๋ ์ด๋ ๋ค๋ฅธ ํจ์๊ฐ ์๋ค๋ฉด ์ด๋ฌํ ์ถ๊ฐ์ ์ํฅ์ ๋ฐ์ต๋๋ค.
์ด๊ฒ์ ์ข์ ์๋ ์์ง๋ง, ์์ข์ ์๋ ์์ต๋๋ค. ์์ข์ ์๋ฅผ ํ๋ฒ ์์ํด๋ด
์๋ค.
์ ์ ๊ฐ ๊ตฌ๋งคํ๊ธฐ ๋ฒํผ์ ๋๋ฌ ๊ตฌ๋งค ํจ์๋ฅผ ํธ์ถํฉ๋๋ค. ์ด๋ ๋คํธ์ํฌ ์์ฒญ์ ์์ฑํ๊ณ ์๋ฒ์ ์ฅ๋ฐ๊ตฌ๋ ๋ฐฐ์ด์ ๋ณด๋
๋๋ค.
ํ์ง๋ง ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด ์ข์ง์์์ ๊ตฌ๋งค ํจ์๋ ๋ค์ํ๋ฒ ๋คํธ์ํฌ ์์ฒญ์ ๋ณด๋ด์ผ ํ๋ ์ํฉ์ด ์๊ฒผ์ต๋๋ค.
์ด๋, ์ฌ์ฉ์๊ฐ ๋คํธ์ํฌ ์์ฒญ์ด ์์๋๊ธฐ ์ ์ ์ค์๋ก ์ํ์ง ์๋ ์ํ์ "์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ" ๋ฒํผ์ ์ค์๋ก ํด๋ฆญํ๋ฉด ์ด๋ป๊ฒ๋ ๊น์?
์ค์๊ฐ ์๊ณ ๋ ๋ค, ๋คํธ์ํฌ ์์ฒญ์ด ์์๋๋ฉด ์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ ํจ์ ๋๋ฌธ์ ์ค์๋ก ๋ณ๊ฒฝ๋ ์ฅ๋ฐ๊ตฌ๋ ๋ฐฐ์ด์ ์๋ฒ์ ๋ณด๋ด๊ฒ ๋ฉ๋๋ค.
๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ๋ ํญ์ ์ฅ๋ฐ๊ตฌ๋ ๋ฐฐ์ด์ ๋ณต์ ํ์ฌ ์์ ํ๊ณ ๋ณต์ ๋ณธ์ ๋ฐํํ๋ ๊ฒ์
๋๋ค.
์ด๋ ๊ฒํ๋ฉด ์ฅ๋ฐ๊ตฌ๋ ์ฐธ์กฐ๋ฅผ ๋ณด์ ํ๊ณ ์๋ ๋ค๋ฅธ ํจ์๊ฐ ๋ค๋ฅธ ๋ณ๊ฒฝ ์ฌํญ์ ์ํฅ์ ๋ฐ์ง ์๊ฒ๋ฉ๋๋ค.
์ด ์ ๊ทผ๋ฒ์๋ํด ๋งํ๊ณ ์ถ์ ๊ฒ์ด ๋๊ฐ์ง ์์ต๋๋ค.
- ์ค์ ๋ก ์ ๋ ฅ๋ ๊ฐ์ฒด๋ฅผ ์์ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ๊ฐ ์์ ์ ์์ง๋ง ์ด๋ฌํ ์์ ๋ฅผ ์๊ฐํด๋ณด๊ณ ์ ์ฉํด๋ณด๋ฉด ๊ทธ๋ฐ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๋ค๋ ๊ฒ์ ๊นจ๋ฌ์ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋๋ถ๋ถ์ ๊ฒ๋ค์ด ์ฌ์ด๋ ์ดํํธ ์์ด ๋ฆฌํฉํ ๋ง ๋ ์ ์์ต๋๋ค.
- ํฐ ๊ฐ์ฒด๋ฅผ ๋ณต์ ํ๋ ๊ฒ์ ์ฑ๋ฅ ์ธก๋ฉด์์ ๊ฐ์ด ๋งค์ฐ ๋น์๋๋ค. ์ด์ข๊ฒ๋ ์ด๋ฐ๊ฒ ํฐ ๋ฌธ์ ๊ฐ ๋์ง๋ ์์ต๋๋ค. ์๋ํ๋ฉด ์ด๋ฌํ ํ๋ก๊ทธ๋๋ฐ ์ ๊ทผ๋ฒ์ ๊ฐ๋ฅํ๊ฒํด์ค ์ข์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ์๋์ผ๋ก ๋ณต์ ํ๋ ๊ฒ์ฒ๋ผ ๋ฉ๋ชจ๋ฆฌ ์ง์ฝ์ ์ด์ง ์๊ฒ ํด์ฃผ๊ณ ๋น ๋ฅด๊ฒ ๋ณต์ ํด์ค๋๋ค.
Bad:
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};Good:
const addItemToCart = (cart, item) => {
return [...cart, { item, date : Date.now() }];
};์ ์ญ ํ๊ฒฝ์ ์ฌ์ฉํ๋ ๊ฒ์ JavaScript์์ ๋์ ๊ดํ์
๋๋ค. ์๋ํ๋ฉด ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๊ณผ์ ์ถฉ๋์ด ์ผ์ด๋ ์ ์๊ณ ,
๋น์ ์ API๋ฅผ ์ฐ๋ ์ ์ ๋ค์ ์ด์ํ๊ฒฝ์์ ์์ธ๊ฐ ๋ฐ์ํ๊ธฐ ์ ๊น์ง๋ ๋ฌธ์ ๋ฅผ ์ธ์งํ์ง ๋ชปํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์
๋๋ค. ์์ ๋ฅผ ํ๋ ์๊ฐํด๋ด
์๋ค.
JavaScript์ ๋ค์ดํฐ๋ธ Array ๋ฉ์๋๋ฅผ ํ์ฅํ์ฌ ๋ ๋ฐฐ์ด ๊ฐ์ ์ฐจ์ด๋ฅผ ๋ณด์ฌ์ค ์์๋ diff ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น์?
์๋ก์ด ํจ์๋ฅผ Array.prototype์ ์ธ ์๋ ์์ง๋ง, ๋๊ฐ์ ์ผ์ ์๋ํ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ถฉ๋ ํ ์ ์์ต๋๋ค.
๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ diff ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ฒซ๋ฒ์งธ ์์์ ๋ง์ง๋ง ์์์ ์ฐจ์ด์ ์ ์ฐพ์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์?
์ด๊ฒ์ด ๊ทธ๋ฅ ES2015/ES6์ classes๋ฅผ ์ฌ์ฉํด์ ์ ์ญ Array๋ฅผ ์์ํด๋ฒ๋ฆฌ๋ ๊ฒ์ด ํจ์ฌ ๋ ๋์ ์ด์ ์
๋๋ค.
์์ข์ ์:
Array.prototype.diff = function diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
};์ข์ ์:
class SuperArray extends Array {
diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
}
}JavaScript๋ Haskell์ฒ๋ผ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ ์๋์ง๋ง ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ฒ๋ผ ์์ฑํ ์ ์์ต๋๋ค. ํจ์ํ ์ธ์ด๋ ๋ ๊น๋ํ๊ณ ํ ์คํธํ๊ธฐ ์ฝ์ต๋๋ค. ๊ฐ๋ฅํ๋ฉด ์ด ๋ฐฉ์์ ์ฌ์ฉํ๋๋ก ํด๋ณด์ธ์.
์์ข์ ์:
const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];
let totalOutput = 0;
for (let i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}์ข์ ์:
const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];
const totalOutput = programmerOutput
.map(programmer => programmer.linesOfCode)
.reduce((acc, linesOfCode) => acc + linesOfCode, INITIAL_VALUE);์์ข์ ์:
if (fsm.state === 'fetching' && isEmpty(listNode)) {
// ...
}์ข์ ์:
function shouldShowSpinner(fsm, listNode) {
return fsm.state === 'fetching' && isEmpty(listNode);
}
if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}์์ข์ ์:
function isDOMNodeNotPresent(node) {
// ...
}
if (!isDOMNodeNotPresent(node)) {
// ...
}์ข์ ์:
function isDOMNodePresent(node) {
// ...
}
if (isDOMNodePresent(node)) {
// ...
}์กฐ๊ฑด๋ฌธ ์์ฑ์ ํผํ๋ผ๋ ๊ฒ์ ๋งค์ฐ ๋ถ๊ฐ๋ฅํ ์ผ๋ก ๋ณด์
๋๋ค. ์ด ์๊ธฐ๋ฅผ ์ฒ์ ๋ฃ๋ ์ฌ๋๋ค์ ๋๋ถ๋ถ "If๋ฌธ ์์ด ์ด๋ป๊ฒ ์ฝ๋๋ฅผ ์ง๋์?"๋ผ๊ณ ๋งํฉ๋๋ค.
ํ์ง๋ง ๋คํ์ฑ์ ์ด์ฉํ๋ค๋ฉด ๋์ผํ ์์
์ ์ํํ ์ ์์ต๋๋ค. ๋๋ฒ์งธ ์ง๋ฌธ์ ๋ณดํต "๋ค ์ข๋ค์ ๊ทผ๋ฐ ๋ด๊ฐ ์ ๊ทธ๋ ๊ฒ ํด์ผํ๋์?"์ด์ฃ .
๊ทธ์ ๋ํ ๋๋ต์, ์์ ์ฐ๋ฆฌ๊ฐ ๊ณต๋ถํ๋ clean code ์ปจ์
์ ์์ต๋๋ค. ํจ์๋ ๋จ ํ๋์ ์ผ๋ง ์ํํ์ฌ์ผ ํฉ๋๋ค.
๋น์ ์ด ํจ์๋ ํด๋์ค์ if๋ฌธ์ ์ด๋ค๋ฉด ๊ทธ๊ฒ์ ๊ทธ ํจ์๋ ํด๋์ค๊ฐ ํ๊ฐ์ง ์ด์์ ์ผ์ ์ํํ๊ณ ์๋ค๊ณ ๋งํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
๊ธฐ์ตํ์ธ์, ํ๋์ ํจ์๋ ๋ฑ ํ๋์ ์ผ๋ง ํด์ผํฉ๋๋ค.
์์ข์ ์:
class Airplane {
// ...
getCruisingAltitude() {
switch (this.type) {
case '777':
return this.getMaxAltitude() - this.getPassengerCount();
case 'Air Force One':
return this.getMaxAltitude();
case 'Cessna':
return this.getMaxAltitude() - this.getFuelExpenditure();
}
}
}์ข์ ์:
class Airplane {
// ...
}
class Boeing777 extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude() - this.getPassengerCount();
}
}
class AirForceOne extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude();
}
}
class Cessna extends Airplane {
// ...
getCruisingAltitude() {
return this.getMaxAltitude() - this.getFuelExpenditure();
}
}JavaScript๋ ํ์ ์ด ์ ํด์ ธ์์ง ์์ต๋๋ค. ์ด๋ ๋น์ ์ ํจ์๊ฐ ์ด๋ค ํ์ ์ ์ธ์๋ ๋ฐ์ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์ด๋ฐ JavaScript์ ์์ ๋ก์ ๋๋ฌธ์ ์ฌ๋ฌ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ์๊ณ ์ด ๋๋ฌธ์ ๋น์ ์ ํจ์์ ํ์ -์ฒดํน์ ์๋ ํ ์๋ ์์ต๋๋ค. ํ์ง๋ง ํ์ -์ฒดํน ๋ง๊ณ ๋ ์ด๋ฌํ ํ๋ฅผ ํผํ ๋ง์ ๋ฐฉ๋ฒ๋ค์ด ์กด์ฌํฉ๋๋ค. ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ผ๊ด์ฑ ์๋ API๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
์์ข์ ์:
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'));
}
}์ข์ ์:
function travelToTexas(vehicle) {
vehicle.move(this.currentLocation, new Location('texas'));
}๋น์ ์ด ๋ฌธ์์ด, ์ ์, ๋ฐฐ์ด๋ฑ ๊ธฐ๋ณธ ์๋ฃํ์ ์ฌ์ฉํ๊ณ ๋คํ์ฑ์ ์ฌ์ฉํ ์ ์์ ๋ ์ฌ์ ํ ํ์
-์ฒดํน์ด ํ์ํ๋ค๊ณ ๋๊ปด์ง๋ค๋ฉด
TypeScript๋ฅผ ๋์
ํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด๋ ๊ฒ์ด ์ข์ต๋๋ค. TypeScript๋ ํ์ค JavaScript ๊ตฌ๋ฌธ์ ์ ์ ํ์
์ ์ ๊ณตํ๋ฏ๋ก
์ผ๋ฐ JavaScript์ ๋์์ผ๋ก ์ฌ์ฉํ๊ธฐ์ ์ข์ต๋๋ค. JavaScript์์ ํ์
-์ฒดํน์ ํ ๋ ๋ฌธ์ ์ ์ ๊ฐ์ง type-safety
๋ฅผ ์ป๊ธฐ์ํด ์์ฑ๋ ์ฝ๋๋ฅผ ์ค๋ช
ํ๊ธฐ ์ํด์ ๋ง์ ์ฃผ์์ ๋ฌ์์ผํ๋ค๋ ์ ์
๋๋ค. JavaScript๋ก ์ฝ๋๋ฅผ ์์ฑํ ๋ ๊น๋ํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ,
์ข์ ํ
์คํธ ์ฝ๋๋ฅผ ์ง์ผํ๋ฉฐ ์ข์ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ํด์ผํฉ๋๋ค. ๊ทธ๋ฌ๊ธฐ ์ซ๋ค๋ฉด ๊ทธ๋ฅ TypeScript(์ด๊ฑด ์ ๊ฐ ๋งํ๋ฏ์ด, ์ข์ ๋์ฒด์ฌ์
๋๋ค!)๋ฅผ ์ฐ์ธ์.
์์ข์ ์:
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');
}์ข์ ์:
function combine(val1, val2) {
return val1 + val2;
}์ต์ ๋ธ๋ผ์ฐ์ ๋ค์ ๋ฐํ์์ ๋ง์ ์ต์ ํ ์์ ์ ์ํํฉ๋๋ค. ๋๋ถ๋ถ ๋น์ ์ด ์ฝ๋๋ฅผ ์ต์ ํ ํ๋ ๊ฒ์ ์๊ฐ๋ญ๋น์ผ ๊ฐ๋ฅ์ฑ์ด ๋ง์ต๋๋ค. ์ต์ ํ๊ฐ ๋ถ์กฑํ ๊ณณ์ด ์ด๋์ง๋ฅผ ์๋ ค์ฃผ๋ ์ข์ ์๋ฃ๊ฐ ์ฌ๊ธฐ ์์ต๋๋ค. ์ด๊ฒ์ ์ฐธ์กฐํ์ฌ ์ต์ ๋ธ๋ผ์ฐ์ ๋ค์ด ์ต์ ํ ํด์ฃผ์ง ์๋ ๋ถ๋ถ๋ง ์ต์ ํ๋ฅผ ํด์ฃผ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์์ข์ ์:
// ์ค๋๋ ๋ธ๋ผ์ฐ์ ์ ๊ฒฝ์ฐ ์บ์๋์ง ์์ `list.length`๋ฅผ ํตํ ๋ฐ๋ณต๋ฌธ์ ๋์ ์ฝ์คํธ๋ฅผ ๊ฐ์ก์ต๋๋ค.
// ๊ทธ ์ด์ ๋ `list.length`๋ฅผ ๋งค๋ฒ ๊ณ์ฐํด์ผ๋ง ํ๊ธฐ ๋๋ฌธ์ธ๋ฐ, ์ต์ ๋ธ๋ผ์ฐ์ ์์๋ ์ด๊ฒ์ด ์ต์ ํ ๋์์ต๋๋ค.
for (let i = 0, len = list.length; i < len; i++) {
// ...
}์ข์ ์:
for (let i = 0; i < list.length; i++) {
// ...
}์ฃฝ์ ์ฝ๋๋ ์ค๋ณต๋ ์ฝ๋ ๋งํผ์ด๋ ์ข์ง ์์ต๋๋ค. ์ฃฝ์ ์ฝ๋๋ ๋น์ ์ ์ฝ๋์ ๋จ์์์ ์ด๋ ํ ์ด์ ๋ ์์ต๋๋ค. ํธ์ถ๋์ง ์๋ ์ฝ๋๊ฐ ์๋ค๋ฉด ๊ทธ ์ฝ๋๋ ์ง์ฐ์ธ์! ๊ทธ ์ฝ๋๊ฐ ์ฌ์ ํ ํ์ํด๋ ๊ทธ ์ฝ๋๋ ๋ฒ์ ํ์คํ ๋ฆฌ์ ์์ ํ๊ฒ ๋จ์์์ ๊ฒ์ ๋๋ค.
์์ข์ ์:
function oldRequestModule(url) {
// ...
}
function newRequestModule(url) {
// ...
}
const req = newRequestModule;
inventoryTracker('apples', req, 'www.inventory-awesome.io');์ข์ ์:
function newRequestModule(url) {
// ...
}
const req = newRequestModule;
inventoryTracker('apples', req, 'www.inventory-awesome.io');JavaScript๋ ์ธํฐํ์ด์ค์ ํ์
์ ๊ฐ์ง๊ณ ์์ง ์๊ณ ์ด๋ฌํ ํจํด์ ์ ์ฉํ๊ธฐ๊ฐ ํ๋ญ๋๋ค.
์๋ํ๋ฉด public์ด๋ private๊ฐ์ ํค์๋๊ฐ ์๊ธฐ ๋๋ฌธ์ด์ฃ .
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ getter ๋ฐ setter๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ๊ฒ์ด ๊ฐ์ฒด์ ์์ฑ์ ์ฐพ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋ซ์ต๋๋ค.
"์์?"๋ผ๊ณ ๋ฌผ์ผ์ค ์๋ ์๊ฒ ์ต๋๋ค. ์ ๊ทธ๋ฐ์ง์ ๋ํด์ ๋ช ๊ฐ์ง ์ด์ ๋ฅผ ๋์์์ด ์ ์ด๋ดค์ต๋๋ค.
- ๊ฐ์ฒด์ ์์ฑ์ ์ป๋ ๊ฒ ์ด์์ ๋ง์ ๊ฒ์ ํ๊ณ ์ถ์ ๋, ์ฝ๋์์ ๋ชจ๋ ์ ๊ทผ์๋ฅผ ์ฐพ์ ๋ฐ๊พธ๊ณ ํ ํ์๊ฐ ์์ต๋๋ค.
setํ ๋ ๊ฒ์ฆ๋ก์ง์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ฝ๋๋ฅผ ๋ ๊ฐ๋จํ๊ฒ ๋ง๋ญ๋๋ค.- ๋ด๋ถ์ฉ API๋ฅผ ์บก์ํ ํ ์ ์์ต๋๋ค.
getting๊ณผsettingํ ๋ ๋ก๊ทธ๋ฅผ ์ฐพ๊ฑฐ๋ ์๋ฌ์ฒ๋ฆฌ๋ฅผ ํ๊ธฐ ์ฝ์ต๋๋ค.- ์๋ฒ์์ ๊ฐ์ฒด ์์ฑ์ ๋ฐ์์ฌ ๋ lazy load ํ ์ ์์ต๋๋ค.
์์ข์ ์:
function makeBankAccount() {
// ...
return {
// ...
balance: 0
};
}
const account = makeBankAccount();
account.balance = 100;์ข์ ์:
function makeBankAccount() {
// private์ผ๋ก ์ ์ธ๋ ๋ณ์
let balance = 0;
// ์๋ return์ ํตํด public์ผ๋ก ์ ์ธ๋ "getter"
function getBalance() {
return balance;
}
// ์๋ return์ ํตํด public์ผ๋ก ์ ์ธ๋ "setter"
function setBalance(amount) {
// ... balance๋ฅผ ์
๋ฐ์ดํธํ๊ธฐ ์ ๊ฒ์ฆ๋ก์ง
balance = amount;
}
return {
// ...
getBalance,
setBalance
};
}
const account = makeBankAccount();
account.setBalance(100);ํด๋ก์ ธ๋ฅผ ์ด์ฉํ๋ฉด ๊ฐ๋ฅํฉ๋๋ค. (ES5 ์ดํ์์๋)
์์ข์ ์:
const Employee = function(name) {
this.name = name;
};
Employee.prototype.getName = function getName() {
return this.name;
};
const employee = new Employee('John Doe');
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: undefined์ข์ ์:
function makeEmployee(name) {
return {
getName() {
return name;
},
};
}
const employee = makeEmployee('John Doe');
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
delete employee.name;
console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe๊ธฐ์กด ES5์ ํด๋์ค์์ ์ดํดํ๊ธฐ ์ฌ์ด ์์, ๊ตฌ์ฑ ๋ฐ ๋ฉ์๋ ์ ์๋ฅผ ํ๋ ๊ฑด ๋งค์ฐ ์ด๋ ต์ต๋๋ค. ๋งค๋ฒ ๊ทธ๋ฐ๊ฒ์ ์๋์ง๋ง ์์์ด ํ์ํ ๊ฒฝ์ฐ๋ผ๋ฉด ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํ์ง๋ง ๋น์ ์ด ํฌ๊ณ ๋ ๋ณต์กํ ๊ฐ์ฒด๊ฐ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด ํด๋์ค๋ณด๋ค ์์ ํจ์๋ฅผ ์ฌ์ฉํ์ธ์.
์์ข์ ์:
const Animal = function(age) {
if (!(this instanceof Animal)) {
throw new Error("Instantiate Animal with `new`");
}
this.age = age;
};
Animal.prototype.move = function() {};
const Mammal = function(age, furColor) {
if (!(this instanceof Mammal)) {
throw new Error("Instantiate Mammal with `new`");
}
Animal.call(this, age);
this.furColor = furColor;
};
Mammal.prototype = Object.create(Animal.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.liveBirth = function liveBirth() {};
const Human = function(age, furColor, languageSpoken) {
if (!(this instanceof Human)) {
throw new Error("Instantiate Human with `new`");
}
Mammal.call(this, age, furColor);
this.languageSpoken = languageSpoken;
};
Human.prototype = Object.create(Mammal.prototype);
Human.prototype.constructor = Human;
Human.prototype.speak = function speak() {};์ข์ ์:
class Animal {
constructor(age) {
this.age = age;
}
move() { /* ... */ }
}
class Mammal extends Animal {
constructor(age, furColor) {
super(age);
this.furColor = furColor;
}
liveBirth() { /* ... */ }
}
class Human extends Mammal {
constructor(age, furColor, languageSpoken) {
super(age, furColor);
this.languageSpoken = languageSpoken;
}
speak() { /* ... */ }
}JavaScript์์ ๋ฉ์๋ ์ฒด์ด๋์ ๋งค์ฐ ์ ์ฉํ ํจํด์ด๋ฉฐ jQuery๋ Lodash๊ฐ์ ๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ด ํจํด์ ์ฐพ์๋ณผ ์ ์์ต๋๋ค. ์ด๋ ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ณ ์ดํดํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด์ค๋๋ค. ์ด๋ฐ ์ด์ ๋ค๋ก ๋ฉ์๋ ์ฒด์ด๋์ ์ฐ๋ ๊ฒ์ ๊ถํ๊ณ , ์ฌ์ฉํด๋ณธ๋ค ์ผ๋ง๋ ์ฝ๋๊ฐ ๊น๋ํด์ก๋์ง ๊ผญ ํ์ธ ํด๋ณด๊ธธ ๋ฐ๋๋๋ค. ํด๋์ค ํจ์์์ ๋จ์ํ ๋ชจ๋ ํจ์์ ๋์ 'this'๋ฅผ ๋ฆฌํดํด์ฃผ๋ ๊ฒ์ผ๋ก ํด๋์ค ๋ฉ์๋๋ฅผ ์ถ๊ฐ๋ก ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.
์์ข์ ์:
class Car {
constructor() {
this.make = 'Honda';
this.model = 'Accord';
this.color = 'white';
}
setMake(make) {
this.make = make;
}
setModel(model) {
this.model = model;
}
setColor(color) {
this.color = color;
}
save() {
console.log(this.make, this.model, this.color);
}
}
const car = new Car();
car.setColor('pink');
car.setMake('Ford');
car.setModel('F-150');
car.save();์ข์ ์:
class Car {
constructor() {
this.make = 'Honda';
this.model = 'Accord';
this.color = 'white';
}
setMake(make) {
this.make = make;
// ๋ฉ๋ชจ: ์ฒด์ด๋์ ์ํด this๋ฅผ ๋ฆฌํดํฉ๋๋ค.
return this;
}
setModel(model) {
this.model = model;
// ๋ฉ๋ชจ: ์ฒด์ด๋์ ์ํด this๋ฅผ ๋ฆฌํดํฉ๋๋ค.
return this;
}
setColor(color) {
this.color = color;
// ๋ฉ๋ชจ: ์ฒด์ด๋์ ์ํด this๋ฅผ ๋ฆฌํดํฉ๋๋ค.
return this;
}
save() {
console.log(this.make, this.model, this.color);
// ๋ฉ๋ชจ: ์ฒด์ด๋์ ์ํด this๋ฅผ ๋ฆฌํดํฉ๋๋ค.
return this;
}
}
const car = new Car()
.setColor('pink')
.setMake('Ford')
.setModel('F-150')
.save();Gang of four์ Design Patterns์์ ์ ๋ช ํ ์ ๋ต์ผ๋ก ๋น์ ์ ๊ฐ๋ฅํ๋ค๋ฉด ์์๋ณด๋ค๋ ์กฐํฉ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์์์ ์ฌ์ฉํ์ ๋ ์ป์ ์ ์๋ ์ด๋๋ณด๋ค ์กฐํฉ์ ์ฌ์ฉํ์ ๋ ์ป์ ์ ์๋ ์ด๋์ด ๋ง๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด ์์น์ ์์ ์ ๋น์ ์ด ๊ณ์ ์์์ ์ฌ์ฉํด์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์ ํ ๋, ๋ง์ฝ ์กฐํฉ์ ์ด์ฉํ๋ฉด ๋ ์ฝ๋๋ฅผ ์ ์งค ์ ์์ง ์์๊น ์๊ฐํด๋ณด๋ผ๋ ๊ฒ์ ์์ต๋๋ค. ๋๋๋ก๋ ์ด๊ฒ์ด ๋ง๋ ์ ๋ต์ด๊ธฐ ๋๋ฌธ์ด์ฃ .
"๊ทธ๋ผ ๋์ฒด ์์์ ์ธ์ ์ฌ์ฉํด์ผ ๋๋ ๊ฑด๊ฐ์?"๋ผ๊ณ ๋ฌผ์ด ๋ณผ ์ ์์ต๋๋ค. ์ด๊ฑด ๋น์ ์ด ์ง๋ฉดํ ๋ฌธ์ ์ํฉ์ ๋ฌ๋ ค์์ง๋ง ์กฐํฉ๋ณด๋ค ์์์ ์ฐ๋๊ฒ ๋ ์ข์ ๋งํ ์์๋ฅผ ๋ช ๊ฐ ๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
- ๋น์ ์ ์์๊ด๊ณ๊ฐ "has-a" ๊ด๊ณ๊ฐ ์๋๋ผ "is-a" ๊ด๊ณ์ผ ๋ (์ฌ๋->๋๋ฌผ vs. ์ ์ ->์ ์ ์ ๋ณด)
- ๊ธฐ๋ฐ ํด๋์ค์ ์ฝ๋๋ฅผ ๋ค์ ์ฌ์ฉํ ์ ์์ ๋ (์ธ๊ฐ์ ๋ชจ๋ ๋๋ฌผ์ฒ๋ผ ์์ง์ผ ์ ์์ต๋๋ค.)
- ๊ธฐ๋ฐ ํด๋์ค๋ฅผ ์์ ํ์ฌ ํ์๋ ํด๋์ค ๋ชจ๋๋ฅผ ์์ ํ๊ณ ์ถ์ ๋ (์ด๋์ ๋ชจ๋ ๋๋ฌผ์ด ์๋นํ๋ ์นผ๋ก๋ฆฌ๋ฅผ ๋ณ๊ฒฝํ๊ณ ์ถ์ ๋)
์์ข์ ์:
class Employee {
constructor(name, email) {
this.name = name;
this.email = email;
}
// ...
}
// ์ด ์ฝ๋๊ฐ ์์ข์ ์ด์ ๋ Employees๊ฐ tax data๋ฅผ "๊ฐ์ง๊ณ " ์๊ธฐ ๋๋ฌธ์
๋๋ค.
// EmployeeTaxData๋ Employee ํ์
์ด ์๋๋๋ค.
class EmployeeTaxData extends Employee {
constructor(ssn, salary) {
super();
this.ssn = ssn;
this.salary = salary;
}
// ...
}์ข์ ์:
class EmployeeTaxData {
constructor(ssn, salary) {
this.ssn = ssn;
this.salary = salary;
}
// ...
}
class Employee {
constructor(name, email) {
this.name = name;
this.email = email;
}
setTaxData(ssn, salary) {
this.taxData = new EmployeeTaxData(ssn, salary);
}
// ...
}Clean Code์์ ๋งํ๊ธธ "ํด๋์ค๋ฅผ ์์ ํ ๋๋ ์์ ํด์ผํ๋ ์ด์ ๊ฐ 2๊ฐ ์ด์ ์์ผ๋ฉด ์๋ฉ๋๋ค". ์ด๊ฒ์ ํ๋์ ํด๋์ค์ ๋ง์ ๊ธฐ๋ฅ์ ์ค์ ๋ฃ๋ ๊ฒ์ด๋ ๋ค๋ฆ ์์ต๋๋ค. ๋ง์น ๋นํ๊ธฐ๋ฅผ ํ๋ ๊ฐ๋ฐฉ์ 1๊ฐ๋ง ๊ฐ์ง๊ณ ํ ์ ์์ ๋ ์ฒ๋ผ ๋ง์ด์ฃ . ์ด ๋ฌธ์ ๋ ๋น์ ์ ํด๋์ค๊ฐ ๊ฐ๋ ์ ์ผ๋ก ์์ง๋์ด ์์ง ์๋ค๋ ๊ฒ์ด๊ณ , ํด๋์ค๋ฅผ ๋ฐ๊ฟ์ผํ ๋ง์ ์ด์ ๊ฐ ๋ฉ๋๋ค. ํด๋์ค๋ฅผ ์์ ํ๋๋ฐ ๋ค์ด๋ ์๊ฐ์ ์ค์ด๋ ๊ฒ์ ์ค์ํฉ๋๋ค. ์๋๋ฉด ํ๋์ ํด๋์ค์ ๋๋ฌด ๋ง์ ๊ธฐ๋ฅ๋ค์ด ์๊ณ ๋น์ ์ด ์ด ์์ ๊ธฐ๋ฅ๋ค์ ์์ ํ ๋ ์ด ์ฝ๋๊ฐ ๋ค๋ฅธ ๋ชจ๋๋ค์ ์ด๋ ํ ์ํฅ์ ๋ผ์น๋์ง ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์์ข์ ์:
class UserSettings {
constructor(user) {
this.user = user;
}
changeSettings(settings) {
if (this.verifyCredentials()) {
// ...
}
}
verifyCredentials() {
// ...
}
}์ข์ ์:
class UserAuth {
constructor(user) {
this.user = user;
}
verifyCredentials() {
// ...
}
}
class UserSettings {
constructor(user) {
this.user = user;
this.auth = new UserAuth(user);
}
changeSettings(settings) {
if (this.auth.verifyCredentials()) {
// ...
}
}
}Bertrand Meyer์ ๋ง์ ์ํ๋ฉด "์ํํธ์จ์ด ๊ฐ์ฒด(ํด๋์ค, ๋ชจ๋, ํจ์ ๋ฑ)๋ ํ์ฅ์ ์ํด ๊ฐ๋ฐฉ์ ์ด์ด์ผ ํ๋ฉฐ ์์ ์์
ํ์์ ์ด์ด์ผ ํฉ๋๋ค." ์ด๊ฒ์ ์๋ฏธ๋ ๋ฌด์์ผ๊น์? ์ด ์๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ์๊ฐ .js ์์ค ์ฝ๋ ํ์ผ์ ์ด์ด ์๋์ผ๋ก ์กฐ์ํ์ง ์๊ณ ๋
๋ชจ๋์ ๊ธฐ๋ฅ์ ํ์ฅํ๋๋ก ํ์ฉํด์ผํ๋ค๊ณ ๋งํฉ๋๋ค.
์์ข์ ์:
class AjaxAdapter extends Adapter {
constructor() {
super();
this.name = 'ajaxAdapter';
}
}
class NodeAdapter extends Adapter {
constructor() {
super();
this.name = 'nodeAdapter';
}
}
class HttpRequester {
constructor(adapter) {
this.adapter = adapter;
}
fetch(url) {
if (this.adapter.name === 'ajaxAdapter') {
return makeAjaxCall(url).then((response) => {
// transform response and return
});
} else if (this.adapter.name === 'httpNodeAdapter') {
return makeHttpCall(url).then((response) => {
// transform response and return
});
}
}
}
function makeAjaxCall(url) {
// request and return promise
}
function makeHttpCall(url) {
// request and return promise
}์ข์ ์:
class AjaxAdapter extends Adapter {
constructor() {
super();
this.name = 'ajaxAdapter';
}
request(url) {
// request and return promise
}
}
class NodeAdapter extends Adapter {
constructor() {
super();
this.name = 'nodeAdapter';
}
request(url) {
// request and return promise
}
}
class HttpRequester {
constructor(adapter) {
this.adapter = adapter;
}
fetch(url) {
return this.adapter.request(url).then((response) => {
// transform response and return
});
}
}์ด๊ฒ์ ๋งค์ฐ ๊ฐ๋จํ์ง๋ง ๊ฐ๋ ฅํ ์์น์ ๋๋ค. ๋ฆฌ์ค์ฝํ ์์น์ด๋ ์๋ฃํ S๊ฐ ์๋ฃํ T์ ํ์ํ์ด๋ผ๋ฉด, ํ๋ก๊ทธ๋จ์ด ๊ฐ์ถ์ด์ผ ํ ์์ฑ๋ค(์ ํ์ฑ, ์ํ๋๋ ์์ ๋ฑ)์ ๋ณ๊ฒฝ์ฌํญ ์์ด, ์๋ฃํ T์ ๊ฐ์ฒด๋ฅผ ์๋ฃํ S์ ๊ฐ์ฒด๋ก ๊ต์ฒด(์นํ)ํ ์ ์์ด์ผ ํ๋ค๋ ์์น์ ๋๋ค.
์ด ์์น์ ์๋ฅผ ๋ค์ด ์ค๋ช ํ์๋ฉด ๋น์ ์ด ๋ถ๋ชจ ํด๋์ค์ ์์ ํด๋์ค๋ฅผ ๊ฐ์ง๊ณ ์์ ๋ ๋ฒ ์ด์ค ํด๋์ค์ ํ์ ํด๋์ค๋ฅผ ์๋ชป๋ ๊ฒฐ๊ณผ ์์ด ์๋ก ๊ตํํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ฌ์ ํ ์ดํด๊ฐ ์๊ฐ๋ค๋ฉด ์ ์ฌ๊ฐํ-์ง์ฌ๊ฐํ ์์ ๋ฅผ ๋ด ์๋ค. ์ํ์ ์ผ๋ก ์ ์ฌ๊ฐํ์ ์ง์ฌ๊ฐํ์ด์ง๋ง ์์์ ํตํด "is-a" ๊ด๊ณ๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ๋งํ๋ค๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
์์ข์ ์:
class Rectangle {
constructor() {
this.width = 0;
this.height = 0;
}
setColor(color) {
// ...
}
render(area) {
// ...
}
setWidth(width) {
this.width = width;
}
setHeight(height) {
this.height = height;
}
getArea() {
return this.width * this.height;
}
}
class Square extends Rectangle {
setWidth(width) {
this.width = width;
this.height = width;
}
setHeight(height) {
this.width = height;
this.height = height;
}
}
function renderLargeRectangles(rectangles) {
rectangles.forEach((rectangle) => {
rectangle.setWidth(4);
rectangle.setHeight(5);
const area = rectangle.getArea(); // ์ ์ฌ๊ฐํ์ผ๋ 25๋ฅผ ๋ฆฌํดํฉ๋๋ค. ํ์ง๋ง 20์ด์ด์ผ ํ๋๊ฒ ๋ง์ต๋๋ค.
rectangle.render(area);
});
}
const rectangles = [new Rectangle(), new Rectangle(), new Square()];
renderLargeRectangles(rectangles);์ข์ ์:
class Shape {
setColor(color) {
// ...
}
render(area) {
// ...
}
}
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height;
}
}
class Square extends Shape {
constructor(length) {
super();
this.length = length;
}
getArea() {
return this.length * this.length;
}
}
function renderLargeShapes(shapes) {
shapes.forEach((shape) => {
const area = shape.getArea();
shape.render(area);
});
}
const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];
renderLargeShapes(shapes);JavaScript๋ ์ธํฐํ์ด์ค๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ์์น๋ค์ฒ๋ผ ๋ฑ ๋ง๊ฒ ์ ์ฉํ ์๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋, JavaScript์ ํ์ ์์คํ ์ด ์๋ค ํ๋๋ผ๋ ์ค์ํ๊ณ ๊ด๊ณ์๋ ์์น์ ๋๋ค.
ISP์ ์ํ๋ฉด "ํด๋ผ์ด์ธํธ๋ ์ฌ์ฉํ์ง ์๋ ์ธํฐํ์ด์ค์ ์์กดํ๋๋ก ๊ฐ์ ๋ฐ์ผ๋ฉด ์๋ฉ๋๋ค." ๋ ํ์ดํ ๋๋ฌธ์ ์ธํฐํ์ด์ค๋ JavaScript์์๋ ์์์ ์ธ ๊ณ์ฝ์ผ ๋ฟ์ ๋๋ค.
JavaScript์์ ์ด๊ฒ์ ๋ณด์ฌ์ฃผ๋ ๊ฐ์ฅ ์ข์ ์๋ ๋ฐฉ๋ํ ์์ ์ค์ ๊ฐ์ฒด๊ฐ ํ์ํ ํด๋์ค์ ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ๋ฐฉ๋ํ ์์ ์ต์ ์ ์ค์ ํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ์๋ํ๋ฉด ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ค์ ๋ค์ด ์ ๋ถ ๋ค ํ์ํ ๊ฑด ์๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ค์ ์ ์ ํ์ ์ผ๋ก ํ ์ ์๋ค๋ฉด "๋ฌด๊ฑฐ์ด ์ธํฐํ์ด์ค(fat interface)"๋ฅผ ๋ง๋๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์์ข์ ์:
class DOMTraverser {
constructor(settings) {
this.settings = settings;
this.setup();
}
setup() {
this.rootNode = this.settings.rootNode;
this.animationModule.setup();
}
traverse() {
// ...
}
}
const $ = new DOMTraverser({
rootNode: document.getElementsByTagName('body'),
animationModule() {} // ์ฐ๋ฆฌ๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ DOM์ ํ์ํ ๋ ์ ๋๋ฉ์ด์
์ด ํ์ํ์ง ์์ต๋๋ค.
// ...
});์ข์ ์:
class DOMTraverser {
constructor(settings) {
this.settings = settings;
this.options = settings.options;
this.setup();
}
setup() {
this.rootNode = this.settings.rootNode;
this.setupOptions();
}
setupOptions() {
if (this.options.animationModule) {
// ...
}
}
traverse() {
// ...
}
}
const $ = new DOMTraverser({
rootNode: document.getElementsByTagName('body'),
options: {
animationModule() {}
}
});์ด ์์น์ ๋๊ฐ์ง ์ค์ํ ์์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- ์์ ๋ชจ๋์ ํ์ ๋ชจ๋์ ์ข ์๋์ด์๋ ์๋ฉ๋๋ค. ๋ ๋ค ์ถ์ํ์ ์์กดํด์ผ ํฉ๋๋ค.
- ์ถ์ํ๋ ์ธ๋ถ์ฌํญ์ ์์กดํ์ง ์์ต๋๋ค. ์ธ๋ถ์ฌํญ์ ์ถ์ํ์ ์ํด ๋ฌ๋ผ์ ธ์ผ ํฉ๋๋ค.
์ฒ์์๋ ์ด๊ฒ์ ์ดํดํ๋๋ฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ํ์ง๋ง ๋ง์ฝ Angular.js๋ก ์์ ํด๋ณธ์ ์ด ์๋ค๋ฉด ์์กด์ฑ ์ฃผ์ (Dependency Injection) ํํ๋ก ์ด ์๋ฆฌ๋ฅผ ๊ตฌํํ ๊ฒ์ ๋ณด์์ ๊ฒ์ ๋๋ค. DIP๋ ๋์ผํ ๊ฐ๋ ์ ์๋์ง๋ง ์์ ๋ชจ๋์ด ํ์ ๋ชจ๋์ ์ธ๋ถ์ฌํญ์ ์์ง ๋ชปํ๊ฒ ํฉ๋๋ค. ์ด๋ ์์กด์ฑ ์ฃผ์ ์ ํตํด ๋ฌ์ฑํ ์ ์์ต๋๋ค. DI์ ์ฅ์ ์ ๋ชจ๋ ๊ฐ์ ์์กด์ฑ์ ๊ฐ์์ํค๋ ๋ฐ์ ์์ต๋๋ค. ๋ชจ๋๊ฐ์ ์์กด์ฑ์ด ๋์์๋ก ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋ง ํ๋๋ฐ ์ด๋ ค์์ง๊ณ ์ด๊ฒ์ ๋งค์ฐ ๋์ ๊ฐ๋ฐ ํจํด๋ค ์ค ํ๋์ ๋๋ค.
์์์ ์ค๋ช
ํ ๊ฒ์ฒ๋ผ JavaScript์๋ ์ธํฐํ์ด์ค๊ฐ ์์ผ๋ฏ๋ก ์ถ์ํ์ ์์กดํ๋ ๊ฒ์ ์์์ ์ธ ์ฝ์์
๋๋ค.
์ด๋ง์ธ์ฆ์จ, ๋ค๋ฅธ ๊ฐ์ฒด๋ ํด๋์ค์ ๋
ธ์ถ๋๋ ๋ฉ์๋์ ์์ฑ์ด ๋ฐ๋ก ์์์ ์ธ ์ฝ์(์ถ์ํ)๊ฐ ๋๋ค๋ ๊ฒ์ด์ฃ .
์๋ ์์ ์์ ์์์ ์ธ ์ฝ์์ InventoryTracker์๋ํ ๋ชจ๋ ์์ฒญ ๋ชจ๋์ด requestItems ๋ฉ์๋๋ฅผ
๊ฐ์ง ๊ฒ์ด๋ผ๋ ์ ์
๋๋ค.
์์ข์ ์:
class InventoryRequester {
constructor() {
this.REQ_METHODS = ['HTTP'];
}
requestItem(item) {
// ...
}
}
class InventoryTracker {
constructor(items) {
this.items = items;
// ์์ข์ ์ด์ : ํน์ ์์ฒญ๋ฐฉ๋ฒ ๊ตฌํ์ ๋ํ ์์กด์ฑ์ ๋ง๋ค์์ต๋๋ค.
// requestItems๋ ํ๊ฐ์ง ์์ฒญ๋ฐฉ๋ฒ์ ํ์๋ก ํฉ๋๋ค.
this.requester = new InventoryRequester();
}
requestItems() {
this.items.forEach(item => {
this.requester.requestItem(item);
});
}
}
const inventoryTracker = new InventoryTracker(['apples', 'bananas']);
inventoryTracker.requestItems();์ข์ ์:
class InventoryTracker {
constructor(items, requester) {
this.items = items;
this.requester = requester;
}
requestItems() {
this.items.forEach(item => {
this.requester.requestItem(item);
});
}
}
class InventoryRequesterV1 {
constructor() {
this.REQ_METHODS = ['HTTP'];
}
requestItem(item) {
// ...
}
}
class InventoryRequesterV2 {
constructor() {
this.REQ_METHODS = ['WS'];
}
requestItem(item) {
// ...
}
}
// ์์กด์ฑ์ ์ธ๋ถ์์ ๋ง๋ค์ด ์ฃผ์
ํด์ค์ผ๋ก์จ,
// ์์ฒญ ๋ชจ๋์ ์๋กญ๊ฒ ๋ง๋ ์น์์ผ ์ฌ์ฉ ๋ชจ๋๋ก ์ฝ๊ฒ ๋ฐ๊ฟ ๋ผ์ธ ์ ์๊ฒ ๋์์ต๋๋ค.
const inventoryTracker = new InventoryTracker(['apples', 'bananas'], new InventoryRequesterV2());
inventoryTracker.requestItems();ํ ์คํธ๋ ๋ฐฐํฌํ๋ ๊ฒ๋ณด๋ค ์ค์ํฉ๋๋ค. ํ ์คํธ ์์ด ๋ฐฐํฌํ๋ค๋ ๊ฒ์ ๋น์ ์ด ์ง๋์ ์ฝ๋๊ฐ ์ธ์ ๋ ์ค์๋ํด๋ ์ด์ํ์ง ์๋ค๋ ์๊ธฐ์ ๊ฐ์ต๋๋ค. ํ ์คํธ์ ์ผ๋ง๋ ์๊ฐ์ ํฌ์ํ ์ง๋ ๋น์ ์ด ํจ๊ป ์ผํ๋ ํ์ ๋ฌ๋ ค์์ง๋ง Coverage๊ฐ 100%๋ผ๋ ๊ฒ์ ๊ฐ๋ฐ์๋ค์๊ฒ ๋์ ์์ ๊ฐ๊ณผ ์๋๊ฐ์ ์ค๋๋ค. ์ด ๋ง์ ํ๋ฅญํ ํ ์คํธ ๋๊ตฌ๋ฅผ ๋ณด์ ํด์ผ ํ๋ ๊ฒ ๋ฟ๋ง ์๋๋ผ ํ๋ฅญํ Coverage ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ผํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ์ง ์๋๋ค๋ ๊ฒ์ ๊ทธ ๋ฌด์๋ ๋ณ๋ช ์ด ๋ ์ ์์ต๋๋ค. ์ฌ๊ธฐ ํ๋ฅญํ๊ณ ๋ง์ JavaScript ํ ์คํธ ํ๋ ์์ํฌ๋ค ์ด ์์ต๋๋ค. ๋น์ ์ ํ์ ๊ธฐํธ์ ๋ง๋ ํ๋ ์์ํฌ๋ฅผ ๊ณ ๋ฅด๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ํ ์คํธ ํ๋ ์์ํฌ๋ฅผ ๊ณจ๋๋ค๋ฉด ์ด์ ๋ถํฐ๋ ํ์ ๋ชฉํ๋ฅผ ๋ชจ๋ ์๋ก์ด ๊ธฐ๋ฅ/๋ชจ๋์ ์งค ๋ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ผ๋ก ํ์ธ์. ๋ง์ฝ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ ๋ฐฉ๋ฒ๋ก (Test Driven Development, TDD)์ด ๋น์ ์๊ฒ ๋ง๋ ๋ฐฉ๋ฒ์ด๋ผ๋ฉด ๊ทธ๊ฑด ํ๋ฅญํ ๊ฐ๋ฐ ๋ฐฉ๋ฒ์ด ๋ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ค์ํ ๊ฒ์ ๋น์ ์ด ์ด๋ ํ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๊ฑฐ๋ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋ง ํ ๋ ๋น์ ์ด ์ ํ Coverage ๋ชฉํ๋ฅผ ๋ฌ์ฑํ๋ ๊ฒ์ ์์ต๋๋ค.
์์ข์ ์:
const assert = require('assert');
describe('MakeMomentJSGreatAgain', () => {
it('handles date boundaries', () => {
let date;
date = new MakeMomentJSGreatAgain('1/1/2015');
date.addDays(30);
assert.equal('1/31/2015', date);
date = new MakeMomentJSGreatAgain('2/1/2016');
date.addDays(28);
assert.equal('02/29/2016', date);
date = new MakeMomentJSGreatAgain('2/1/2015');
date.addDays(28);
assert.equal('03/01/2015', date);
});
});์ข์ ์:
const assert = require('assert');
describe('MakeMomentJSGreatAgain', () => {
it('handles 30-day months', () => {
const date = new MakeMomentJSGreatAgain('1/1/2015');
date.addDays(30);
assert.equal('1/31/2015', date);
});
it('handles leap year', () => {
const date = new MakeMomentJSGreatAgain('2/1/2016');
date.addDays(28);
assert.equal('02/29/2016', date);
});
it('handles non-leap year', () => {
const date = new MakeMomentJSGreatAgain('2/1/2015');
date.addDays(28);
assert.equal('03/01/2015', date);
});
});Callback์ ๊น๋ํ์ง ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์์ฒญ๋๊ฒ ๋ง์ ์ค๊ดํธ ์ค์ฒฉ์ ๋ง๋ค์ด ๋ ๋๋ค. ES2015/ES6์์ Promise๊ฐ ๋ด์ฅ๋์ด ์์ต๋๋ค. ์ด๊ฑธ ์ฐ์ธ์!
์์ข์ ์:
require('request').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', (requestErr, response) => {
if (requestErr) {
console.error(requestErr);
} else {
require('fs').writeFile('article.html', response.body, (writeErr) => {
if (writeErr) {
console.error(writeErr);
} else {
console.log('File written');
}
});
}
});์ข์ ์:
require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
.then((response) => {
return require('fs-promise').writeFile('article.html', response);
})
.then(() => {
console.log('File written');
})
.catch((err) => {
console.error(err);
});Promise๋ Callback์ ๋นํด ์ ๋ง ๊น๋ํ์ง๋ง ES2017/ES8์์ async์ await์ด ์์ต๋๋ค.
์ด๋ค์ Callback์๋ํ ๋์ฑ ๊น๋ํ ํด๊ฒฐ์ฑ
์ ์ค๋๋ค. ์ค์ง ํ์ํ ๊ฒ์ ํจ์์์ async๋ฅผ ๋ถ์ด๋ ๊ฒ ๋ฟ์
๋๋ค.
๊ทธ๋ฌ๋ฉด ํจ์๋ฅผ ๋
ผ๋ฆฌ์ ์ผ๋ก ์ฐ๊ฒฐํ๊ธฐ์ํด ๋์ด์ then์ ์ฐ์ง ์์๋ ๋ฉ๋๋ค.
๋ง์ฝ ๋น์ ์ด ES2017/ES8 ์ฌ์ฉํ ์ ์๋ค๋ฉด ์ด๊ฒ์ ์ฌ์ฉํ์ธ์!
์์ข์ ์:
require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
.then(response => {
return require('fs-promise').writeFile('article.html', response);
})
.then(() => {
console.log('File written');
})
.catch(err => {
console.error(err);
})์ข์ ์:
async function getCleanCodeArticle() {
try {
const response = await require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
await require('fs-promise').writeFile('article.html', response);
console.log('File written');
} catch(err) {
console.error(err);
}
}์๋ฌ๋ฅผ ๋ฑ๋๋ค๋ ๊ฒ์ ์ข์ ๊ฒ์ ๋๋ค! ์ฆ, ํ๋ก๊ทธ๋จ์์ ๋ฌด์ธ๊ฐ๊ฐ ์๋ชป๋์์ ๋ ๋ฐํ์์์ ์ฑ๊ณต์ ์ผ๋ก ํ์ธ๋๋ฉด ํ์ฌ ์คํ์์ ํจ์ ์คํ์ ์ค๋จํ๊ณ (๋ ธ๋์์) ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํ๊ณ ์คํ ์ถ์ ์ผ๋ก ์ฝ์์์ ์ฌ์ฉ์์๊ฒ ๊ทธ ์ด์ ๋ฅผ ์๋ ค์ค๋๋ค.
๋จ์ํ ์๋ฌ๋ฅผ ํ์ธํ๋ ๊ฒ๋ง์ผ๋ก ๊ทธ ์๋ฌ๊ฐ ํด๊ฒฐ๋๊ฑฐ๋ ๋์ ํ ์ ์๊ฒ ๋๋ ๊ฒ์ ์๋๋๋ค.
console.log๋ฅผ ํตํด ์ฝ์์ ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํ๋ ๊ฒ์ ์๋ฌ ๋ก๊ทธ๋ฅผ ์์ด๋ฒ๋ฆฌ๊ธฐ ์ฝ๊ธฐ ๋๋ฌธ์ ์ข์ ๋ฐฉ๋ฒ์ด ์๋๋๋ค.
๋ง์ฝ์ try/catch๋ก ์ด๋ค ์ฝ๋๋ฅผ ๊ฐ์๋ค๋ฉด ๊ทธ๊ฑด ๋น์ ์ด ๊ทธ ์ฝ๋์ ์ด๋ค ์๋ฌ๊ฐ ๋ ์ง๋ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ๊ฐ์ผ ๊ฒ์ด๋ฏ๋ก
๊ทธ์๋ํ ๊ณํ์ด ์๊ฑฐ๋ ์ด๋ ํ ์ฅ์น๋ฅผ ํด์ผํฉ๋๋ค.
์์ข์ ์:
try {
functionThatMightThrow();
} catch (error) {
console.log(error);
}์ข์ ์:
try {
functionThatMightThrow();
} catch (error) {
// ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ console.error๋ฅผ ์ด์ฉํ๋ ๊ฒ์
๋๋ค. ์ด๊ฑด console.log๋ณด๋ค ์กฐ๊ธ ๋ ์์์ฑ๊ธฐ ์ฝ์ต๋๋ค.
console.error(error);
// ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ ์ ์๊ฒ ์๋ฆฌ๋ ๋ฐฉ๋ฒ์
๋๋ค.
notifyUserOfError(error);
// ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์๋น์ค ์์ฒด์ ์๋ฌ๋ฅผ ๊ธฐ๋กํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
reportErrorToService(error);
// ํน์ ๊ทธ ์ด๋ค ๋ฐฉ๋ฒ์ด ๋ ์ ์์ต๋๋ค.
}์์ ์์น๊ณผ ๊ฐ์ ์ด์ ์ ๋๋ค.
์์ข์ ์:
getdata()
.then(data => {
functionThatMightThrow(data);
})
.catch(error => {
console.log(error);
});์ข์ ์:
getdata()
.then(data => {
functionThatMightThrow(data);
})
.catch(error => {
// ์ฒซ๋ฒ์งธ ๋ฐฉ๋ฒ์ console.error๋ฅผ ์ด์ฉํ๋ ๊ฒ์
๋๋ค. ์ด๊ฑด console.log๋ณด๋ค ์กฐ๊ธ ๋ ์์์ฑ๊ธฐ ์ฝ์ต๋๋ค.
console.error(error);
// ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ ์ ์๊ฒ ์๋ฆฌ๋ ๋ฐฉ๋ฒ์
๋๋ค.
notifyUserOfError(error);
// ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์๋น์ค ์์ฒด์ ์๋ฌ๋ฅผ ๊ธฐ๋กํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
reportErrorToService(error);
// ํน์ ๊ทธ ์ด๋ค ๋ฐฉ๋ฒ์ด ๋ ์ ์์ต๋๋ค.
});ํฌ๋งทํ ์ ์ฃผ๊ด์ ์ ๋๋ค. ์ฌ๊ธฐ์ ์๋ ๋ง์ ๊ท์น๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ๋ฅด๊ธฐ ์ฌ์ด ๊ท์น๋ค์ด ์์ต๋๋ค. ์ฌ๊ธฐ์ ์์์ผ ํ ๊ฒ์ ํฌ๋งทํ ์ ๋ํด ๊ณผ๋ํ๊ฒ ์ ๊ฒฝ์ฐ๋ ๊ฒ์ ์๋ฏธ์๋ค๋ ๊ฒ์ ๋๋ค. ํฌ๋งทํ ์ฒดํฌ๋ฅผ ์๋์ผ๋ก ํด์ฃผ๋ ๋ง์ ๋๊ตฌ๋ค์ด ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด์ค ํ๋๋ฅผ ๊ณจ๋ผ ์ฌ์ฉํ์ธ์. ๊ฐ๋ฐ์๋ค๋ผ๋ฆฌ ํฌ๋งทํ ์๋ํด ๋ ผ์ํ๋ ๊ฒ๋งํผ ์๊ฐ๊ณผ ๋์ ๋ญ๋นํ๋ ๊ฒ์ด ์์ต๋๋ค.
์๋์ผ๋ก ์์์ ๊ต์ ํด์ฃผ๋ ๊ฒ(๋ค์ฌ์ฐ๊ธฐ, ํญ์ด๋ ์คํ์ด์ค๋, ์์ ๋ฐ์ดํ๋ ํฐ๋ฐ์ดํ๋)์ ํด๋นํ์ง ์๋ ์ฌํญ์ ๋ํด์๋ ๋ช๊ฐ์ง ์ง์นจ์ ๋ฐ๋ฅด๋ ๊ฒ์ด ์ข์ต๋๋ค.
JavaScript์๋ ์ ํด์ง ํ์ ์ด ์๊ธฐ ๋๋ฌธ์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๋ ๊ฒ์ผ๋ก ๋น์ ์ ๋ณ์๋ ํจ์๋ช ๋ฑ์์ ๋ง์ ๊ฒ์ ์ ์ ์์ต๋๋ค. ์ด ๊ท์น ๋ํ ์ฃผ๊ด์ ์ด๊ธฐ ๋๋ฌธ์ ๋น์ ์ด ํ์ด ์ ํํ ๊ท์น๋ค์ ๋ฐ๋ฅด์ธ์ ์ค์ํ๊ฑด ํญ์ ์ผ๊ด์ฑ ์๊ฒ ์ฌ์ฉํด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
์์ข์ ์:
const DAYS_IN_WEEK = 7;
const daysInMonth = 30;
const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];
function eraseDatabase() {}
function restore_database() {}
class animal {}
class Alpaca {}์ข์ ์:
const DAYS_IN_WEEK = 7;
const DAYS_IN_MONTH = 30;
const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];
function eraseDatabase() {}
function restoreDatabase() {}
class Animal {}
class Alpaca {}์ด๋ค ํจ์๊ฐ ๋ค๋ฅธ ํจ์๋ฅผ ํธ์ถํ๋ฉด ๊ทธ ํจ์๋ค์ ์์ค ํ์ผ ์์์ ์๋ก ์์ง์ผ๋ก ๊ทผ์ ํด ์์ด์ผ ํฉ๋๋ค. ์ด์์ ์ผ๋ก๋ ํจ์ ํธ์ถ์๋ฅผ ํจ์ ํผํธ์ถ์ ๋ฐ๋ก ์์ ์์น์์ผ์ผ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ฝ๋๋ฅผ ์ฝ์๋ ์ ๋ฌธ์ ์ฝ๋ฏ ์์์ ์๋๋ก ์ฝ๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ์์ฑ ํ ๋๋ ์ฝ์ ๋๋ฅผ ๊ณ ๋ คํ์ฌ ์์ฑ ํด์ผํฉ๋๋ค.
์์ข์ ์:
class PerformanceReview {
constructor(employee) {
this.employee = employee;
}
lookupPeers() {
return db.lookup(this.employee, 'peers');
}
lookupManager() {
return db.lookup(this.employee, 'manager');
}
getPeerReviews() {
const peers = this.lookupPeers();
// ...
}
perfReview() {
this.getPeerReviews();
this.getManagerReview();
this.getSelfReview();
}
getManagerReview() {
const manager = this.lookupManager();
}
getSelfReview() {
// ...
}
}
const review = new PerformanceReview(user);
review.perfReview();์ข์ ์:
class PerformanceReview {
constructor(employee) {
this.employee = employee;
}
perfReview() {
this.getPeerReviews();
this.getManagerReview();
this.getSelfReview();
}
getPeerReviews() {
const peers = this.lookupPeers();
// ...
}
lookupPeers() {
return db.lookup(this.employee, 'peers');
}
getManagerReview() {
const manager = this.lookupManager();
}
lookupManager() {
return db.lookup(this.employee, 'manager');
}
getSelfReview() {
// ...
}
}
const review = new PerformanceReview(employee);
review.perfReview();์ฃผ์์ ๋ค๋๊ฒ์ ์ฌ๊ณผํด์ผํ ์ผ์ด๋ฉฐ ํ์์ ์ธ ๊ฒ์ด ์๋๋๋ค. ์ข์ ์ฝ๋๋ ์ฝ๋ ์์ฒด๋ก ๋งํฉ๋๋ค.
์์ข์ ์:
function hashIt(data) {
// ์ด๊ฑด ํด์ฌ์
๋๋ค.
let hash = 0;
// lengh๋ data์ ๊ธธ์ด์
๋๋ค.
const length = data.length;
// ๋ฐ์ดํฐ์ ๋ฌธ์์ด ๊ฐ์๋งํผ ๋ฐ๋ณต๋ฌธ์ ์คํํฉ๋๋ค.
for (let i = 0; i < length; i++) {
// ๋ฌธ์์ด ์ฝ๋๋ฅผ ์ป์ต๋๋ค.
const char = data.charCodeAt(i);
// ํด์ฌ๋ฅผ ๋ง๋ญ๋๋ค.
hash = ((hash << 5) - hash) + char;
// 32-bit ์ ์๋ก ๋ฐ๊ฟ๋๋ค.
hash &= hash;
}
}์ข์ ์:
function hashIt(data) {
let hash = 0;
const length = data.length;
for (let i = 0; i < length; i++) {
const char = data.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
// 32-bit ์ ์๋ก ๋ฐ๊ฟ๋๋ค.
hash &= hash;
}
}๋ฒ์ ๊ด๋ฆฌ ๋๊ตฌ๊ฐ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ์ฃผ์์ผ๋ก ๋จ๊ธธ ์ด์ ๊ฐ ์์ต๋๋ค.
์์ข์ ์:
doStuff();
// doOtherStuff();
// doSomeMoreStuff();
// doSoMuchStuff();์ข์ ์:
doStuff();๋ฒ์ ๊ด๋ฆฌ ๋๊ตฌ๋ฅผ ์ด์ฉํด์ผํ๋ ๊ฒ์ ๊ผญ ๊ธฐ์ตํ์ธ์. ์ฃฝ์ ์ฝ๋๋ ๋ถํ์ํ ์ค๋ช
๋ ํนํ ์ฝ๋์ ๊ธฐ๋ก์ ๋ํ ์ฃผ์๋
ํ์ํ์ง ์์ต๋๋ค. ์ฝ๋์ ๊ธฐ๋ก์ ๋ํด ๋ณด๊ณ ์ถ๋ค๋ฉด git log๋ฅผ ์ฌ์ฉํ์ธ์!
์์ข์ ์:
/**
* 2016-12-20: ๋ชจ๋๋ ์ ๊ฑฐํ์, ์ดํด๋ ๋์ง ์์ (RM)
* 2016-10-01: ๋ชจ๋๋ ์ฐ๋ ๋ก์ง ๊ฐ์ (JP)
* 2016-02-03: ํ์
์ฒดํน ํ๋๋ถ๋ถ ์ ๊ฑฐ (LI)
* 2015-03-14: ๋ฒ๊ทธ ์์ (JR)
*/
function combine(a, b) {
return a + b;
}์ข์ ์:
function combine(a, b) {
return a + b;
}์ด๊ฑด ์ ๋ง ์ธ๋ฐ ์์ต๋๋ค. ์ ์ ํ ๋ค์ฌ์ฐ๊ธฐ์ ํฌ๋งทํ ์ ํ๊ณ ํจ์์ ๋ณ์์ ์ด๋ฆ์ ์๋ฏธ๋ฅผ ๋ถ์ฌํ์ธ์.
์์ข์ ์:
////////////////////////////////////////////////////////////////////////////////
// ์ค์ฝํ ๋ชจ๋ธ ์ ์
////////////////////////////////////////////////////////////////////////////////
$scope.model = {
menu: 'foo',
nav: 'bar'
};
////////////////////////////////////////////////////////////////////////////////
// actions ์ค์
////////////////////////////////////////////////////////////////////////////////
const actions = function() {
// ...
};์ข์ ์:
$scope.model = {
menu: 'foo',
nav: 'bar'
};
const actions = function() {
// ...
};