우아한 JS 코드 작성 방법
변수
의미 있고 발음 가능한 변수 이름 사용하기
//
const yyyymmdstr = moment().format("YYYY/MM/DD");
//
const currentDate = moment().format("YYYY/MM/DD");
같은 유형의 변수에 대해 같은 어휘를 사용하다
//
getUserInfo();
getClientData();
getCustomerRecord();
//
getUser();
검색 가능한 이름 사용하기
우리가 읽는 것은 우리가 쓰는 것보다 훨씬 많기 때문에 너무 함부로 이름을 지으면 후속 유지보수에 어려움을 가져올 뿐만 아니라 우리 코드를 읽는 개발자에게도 해를 끼칠 수 있다.버디처럼 변수 이름을 읽을 수 있습니다.js와 ESLint 같은 도구는 이름이 지정되지 않은 상수를 식별하는 데 도움을 줄 수 있습니다.
//
// 86400000 ?
setTimeout(blastOff, 86400000);
//
const MILLISECONDS_IN_A_DAY = 86_400_000;
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 = ["Austin", "New York", "San Francisco"];
locations.forEach(l => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
// ,“l” ?
dispatch(l);
//
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(location => {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
dispatch(location);
});
불필요한 컨텍스트를 추가할 필요가 없습니다.
클래스 이름/개체 이름이 설명되어 있으면 변수 이름에서 중복할 필요가 없습니다.
//
const Car = {
carMake: "Honda",
carModel: "Accord",
carColor: "Blue"
};
function paintCar(car) {
car.carColor = "Red";
}
//
const Car = {
make: "Honda",
model: "Accord",
color: "Blue"
};
function paintCar(car) {
car.color = "Red";
}
기본 매개변수를 사용하여 논리 또는 (및) 연산 대체
//
function createMicrobrewery(name) {
const breweryName = name || "Hipster Brew Co.";
// ...
}
//
function createMicrobrewery(name = "Hipster Brew Co.") {
// ...
}
함수
함수 매개 변수(이상적으로 2개 이상)
함수 매개 변수의 수량을 제한하는 것은 매우 중요하다. 왜냐하면 그것은 테스트 함수를 더욱 쉽게 하기 때문이다.만약 세 개 이상의 파라미터가 있다면 조합 폭발을 초래할 수 있으므로 반드시 각각의 단독 파라미터로 대량의 다른 상황을 테스트해야 한다.
하나 또는 두 개의 매개 변수는 이상적인 상황입니다. 가능하다면 세 개의 매개 변수를 피해야 합니다.그 외에 합병해야 한다.대부분의 경우, 세 개 이상의 매개 변수는 대상으로 대체할 수 있다.
//
function createMenu(title, body, buttonText, cancellable) {
// ...
}
createMenu("Foo", "Bar", "Baz", true);
//
function createMenu({ title, body, buttonText, cancellable }) {
// ...
}
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
});
함수는 한 가지 일만 해야 한다
이것은 지금까지 소프트웨어 공학에서 가장 중요한 규칙이다.함수가 한 가지 일에 그치지 않을 때, 그것들은 조합, 테스트, 추리가 더욱 어렵다.하나의 함수를 하나의 조작으로 격리할 수 있을 때 쉽게 재구성할 수 있고 코드도 더욱 명확하게 읽을 수 있다.
//
function emailClients(clients) {
clients.forEach(client => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
//
function emailActiveClients(clients) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
함수 이름은 그 작용을 설명해야 한다
//
function addToDate(date, month) {
// ...
}
const date = new Date();
//
addToDate(date, 1);
//
function addMonthToDate(month, date) {
// ...
}
const date = new Date();
addMonthToDate(1, date);
함수는 추상적인 차원만 있어야 한다
이상의 추상적인 차원 함수가 있다면 이 함수가 너무 많이 만들어졌다는 것을 의미한다. 함수를 분리하면 중용성과 더욱 간단한 테스트를 실현할 수 있다.
//
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 parseBetterJSAlternative(code) {
const tokens = tokenize(code);
const syntaxTree = parse(tokens);
syntaxTree.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 parse(tokens) {
const syntaxTree = [];
tokens.forEach(token => {
syntaxTree.push(/* ... */);
});
return syntaxTree;
}
중복 코드 삭제
가능한 한 중복된 코드를 피해야 한다. 중복된 코드는 좋지 않다. 이것은 우리가 어떤 논리를 바꾸려면 많은 부분을 바꾸어야 한다는 것을 의미한다.
일반적으로 중복된 코드가 있는 것은 두 개 혹은 여러 개의 약간 다른 사물이 있기 때문이다. 그것들은 공통점이 많지만, 그것들 사이의 차이는 우리로 하여금 두 개 또는 여러 개의 독립된 함수를 작성하여 많은 같은 일을 완성하게 한다.중복된 코드를 삭제하는 것은 하나의 함수/모듈/클래스만으로 이 서로 다른 사물을 처리할 수 있는 추상적인 것을 만드는 것을 의미한다.
정확한 추상을 얻는 것이 중요하다. 이것이 바로 우리가 클래스 부분에 열거된 SOLID 원칙을 따라야 하는 이유이다.나쁜 추상은 중복된 코드보다 더 나쁠 수 있으니 조심해라!이렇게 많이 말했는데, 만약 네가 좋은 추상을 할 수 있다면, 가서 해라!너 자신을 반복하지 마라. 그렇지 않으면 언제든지 한 가지 일을 바꾸고 싶을 때 여러 곳을 업데이트해야 한다는 것을 알게 될 것이다.
디자인 모델의 6가지 원칙은 다음과 같다.
나쁜 작법
function showDeveloperList(developers) {
developers.forEach(developer => {
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();
const data = {
expectedSalary,
experience
};
switch (employee.type) {
case "manager":
data.portfolio = employee.getMBAProjects();
break;
case "developer":
data.githubLink = employee.getGithubLink();
break;
}
render(data);
});
}
Object를 사용합니다.assign 기본 객체 설정
나쁜 작법
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",
// User did not include 'body' key
buttonText: "Send",
cancellable: true
};
function createMenu(config) {
config = Object.assign(
{
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
},
config
);
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// ...
}
createMenu(menuConfig);
플래그를 함수 매개 변수로 사용하지 마십시오.
로고는 사용자에게 이 함수는 여러 가지 임무를 완성할 수 있고 함수는 한 가지 일을 해야 한다고 알려준다.함수가 부울 기반의 다른 코드 경로를 따른다면 분리하십시오.
//
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}`);
}
부작용 피하기 (1부분)
함수가 한 값을 받아들여 다른 값이나 여러 값을 되돌려 주는 것 외에 다른 작업을 하지 않으면 부작용이 발생할 수 있다.부작용은 파일을 작성하거나 전체적인 변수를 수정하거나 부주의로 당신의 모든 자금을 낯선 사람에게 송금하는 것일 수도 있다.
나쁜 작법
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'];
부작용 피하기 (두 번째 부분)
JavaScript에서 원래 유형 값은 값에 따라 전달되고 객체/배열은 참조에 따라 전달됩니다.객체 및 배열에 대해 카트 배열에서 함수가 변경된 경우 (예: 구입할 품목 추가) 카트 배열을 사용하는 다른 함수는 이 추가에 영향을 받습니다.그것은 아주 좋을 수도 있지만, 좋지 않을 수도 있다.최악의 상황을 상상해 보자.
사용자가'구매'단추를 누르면 이 단추는purchase 함수를 호출합니다. 이어서 이 함수는 네트워크 요청을 보내고 카트 그룹을 서버에 보냅니다.네트워크 연결이 좋지 않기 때문에purchase 함수는 끊임없이 요청을 다시 시도해야 합니다.현재 인터넷 요청이 시작되기 전에 사용자가 실제로 필요하지 않은 항목에 있는'쇼핑카에 추가'단추를 실수로 눌렀다면 어떻게 해야 합니까?이러한 상황이 발생하고 인터넷 요청이 시작되면 구매 함수는 의외로 추가된 상품을 발송합니다. 쇼핑 카트 그룹에 대한 인용이 있기 때문에addItem ToCart 함수는 추가를 통해 이 쇼핑 카트 그룹을 수정했습니다.
좋은 해결 방안은addItemToCart가 항상 카트 그룹을 복제하고 편집한 후에 복제로 돌아가는 것입니다.따라서 카트가 참조하는 다른 함수가 변경되지 않도록 할 수 있습니다.
이 방법에 관해서는 두 가지 주의해야 할 것이 있다.
1. 어떤 상황에서 우리는 입력 대상을 수정해야 할 수도 있지만, 우리가 이런 프로그래밍 실천을 할 때 이런 상황은 매우 드물고 대부분의 물건은 부작용이 없는 것으로 개조될 수 있다는 것을 발견할 수 있다.
2. 성능상 큰 개체 복제는 비용이 많이 들 수 있습니다.다행히도 실천에서 이것은 큰 문제가 아니다. 왜냐하면 이런 프로그래밍 방법이 신속하게 진행될 수 있고 수동 복제 대상과 그룹처럼 대량의 메모리를 차지하지 않기 때문이다.
//
const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};
//
const addItemToCart = (cart, item) => {
return [...cart, { item, date: Date.now() }];
};
전역 함수 쓰지 마세요.
전역 변수를 오염시키는 것은 JS에서 좋지 않은 방법이다. 왜냐하면 다른 라이브러리와 충돌할 수 있고 그들의 생산에서 이상이 발생하기 전에 API 사용자는 쓸모가 없기 때문이다.예를 들어 JS의 원생 Array 방법을 확장하여 두 개의 그룹 간의 차이를 나타낼 수 있는 diff 방법을 가지고 싶다면 어떻게 해야 합니까?새 함수를 Array에 쓸 수 있습니다.prototype, 그러나 같은 동작을 시도하는 다른 라이브러리와 충돌할 수 있습니다.만약 다른 라이브러리에서 diff만 사용하여 그룹의 첫 번째 요소와 마지막 요소 간의 차이를 찾으면 어떻게 합니까?이것이 바로 ES6 클래스만 사용하고 간단하게 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.reduce(
(totalLines, output) => totalLines + output.linesOfCode,
0
);
포장 조건
//
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문구가 없으면 내가 어떻게 어떤 일을 할 수 있겠는가?"라고 말할 것이다.답은 같은 임무를 수행하기 위해 많은 상황에서 다태성을 사용할 수 있다는 것이다.
두 번째 문제는 통상적으로 "그건 좋은데, 내가 왜 그랬을까?"답은 위에서 말한 개념이다. 함수는 한 가지 일만 해야 한다.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는 유형이 없으며 함수는 모든 유형의 매개변수를 수용할 수 있습니다.때때로 q우리는 이러한 자유에 시달리고 함수에서 유형 검사를 하고 싶습니다.이렇게 하는 것을 피할 수 있는 많은 방법이 있다.우선 일관된 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"));
}
지나치게 최적화하지 마라
현대 브라우저는 운행할 때 대량의 최적화 작업을 했다.만약 당신이 최적화하고 있다면, 당신은 단지 시간을 낭비하고 있을 뿐이다.최적화가 부족한 곳을 볼 수 있는 좋은 자원이 있습니다. 우리는 최적화가 필요한 곳만 찾으면 됩니다.
//
// , “list.length”
// “list.length” 。 ,
for (let i = 0, len = list.length; i < len; i++) {
// ...
}
//
for (let i = 0; i < list.length; i++) {
// ...
}
다음은 우아한 JS 코드에 대한 상세한 내용을 어떻게 쓰는지, 우아한 JS 코드에 대한 더 많은 자료는 저희 다른 관련 글에 주목하세요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JS 판단 수조 네 가지 실현 방법 상세그러면 본고는 주로 몇 가지 판단 방식과 방식 판단의 원리를 바탕으로 문제가 있는지 토론하고자 한다. 예를 들어 html에 여러 개의 iframe 대상이 있으면 instanceof의 검증 결과가 기대에 부합되지 않을...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.