JavaScript에서 기본값을 설정할 때 자주 사용하는 방식은 다음 세 가지입니다.
value = value || "default";
value = value ?? "default";
function hello(name = "User") {
console.log(name);
}겉보기에는 비슷해 보이지만, 실제 동작 방식은 다릅니다. 특히 "", 0, false, null, undefined 같은 값을 다룰 때 결과가 달라지므로 주의해야 합니다.
1. || 연산자로 기본값 설정하기
가장 전통적으로 많이 사용된 방식입니다.
let userName = inputUserName || "Guest";
console.log(userName);inputUserName이 비어 있거나 사용할 수 없는 값이면 "Guest"를 사용합니다.
다만 여기서 중요한 점은 ||가 null이나 undefined만 확인하는 것이 아니라, falsy 값 전체를 기준으로 동작한다는 점입니다. JavaScript의 || 연산자는 불리언 값뿐 아니라 실제 피연산자 값 중 하나를 반환할 수 있습니다. (MDN Web Docs)
2. ||에서 기본값으로 대체되는 값
다음 값들은 JavaScript에서 falsy 값으로 평가됩니다.
false
0
""
null
undefined
NaN따라서 아래 코드는 모두 기본값을 사용합니다.
console.log("" || "Guest"); // "Guest"
console.log(0 || 100); // 100
console.log(false || true); // true
console.log(null || "default"); // "default"
console.log(undefined || "default"); // "default"
console.log(NaN || 0); // 0이 방식은 “빈 문자열도 입력되지 않은 값으로 처리하겠다”는 의도가 있을 때는 유용합니다.
하지만 0, false, ""도 정상적인 값으로 취급해야 하는 경우에는 문제가 될 수 있습니다.
3. 기존 예제 검증
원래 코드입니다.
function greetUser(name, greeting) {
name = name || "User";
greeting = greeting || "Hello";
console.log(greeting + ", " + name + "!");
}
greetUser("Alice", "Hi"); // "Hi, Alice!" 출력
greetUser("", "Hi"); // "Hi, User!" 출력
greetUser("Alice"); // "Hello, Alice!" 출력이 코드는 정상적으로 동작합니다.
다만 greetUser("", "Hi")에서 빈 문자열 ""은 falsy 값이므로 "User"로 대체됩니다.
즉, 이 코드는 다음 정책을 가진 코드입니다.
이름이
"",null,undefined,0,false,NaN처럼 falsy 값이면"User"로 처리한다.
이 정책이 의도한 것이라면 || 사용은 적절합니다.
4. ?? 연산자로 더 안전하게 기본값 설정하기
??는 nullish coalescing operator라고 부릅니다.
??는 왼쪽 값이 null 또는 undefined일 때만 오른쪽 기본값을 사용합니다. 0, false, ""는 그대로 유지합니다. (MDN Web Docs)
console.log("" ?? "Guest"); // ""
console.log(0 ?? 100); // 0
console.log(false ?? true); // false
console.log(null ?? "default"); // "default"
console.log(undefined ?? "default"); // "default"||와 비교하면 차이가 명확합니다.
console.log("" || "Guest"); // "Guest"
console.log("" ?? "Guest"); // ""
console.log(0 || 100); // 100
console.log(0 ?? 100); // 0
console.log(false || true); // true
console.log(false ?? true); // false따라서 값이 아예 없을 때만 기본값을 적용하고 싶다면 ||보다 ??가 더 적절합니다.
5. 기본 매개변수 사용하기
JavaScript 함수에서는 기본 매개변수를 사용할 수 있습니다.
function greetUser(name = "User", greeting = "Hello") {
console.log(greeting + ", " + name + "!");
}
greetUser("Alice", "Hi"); // "Hi, Alice!"
greetUser("Alice"); // "Hello, Alice!"
greetUser(); // "Hello, User!"기본 매개변수는 인자가 전달되지 않았거나 undefined가 전달된 경우에만 적용됩니다. (MDN Web Docs)
즉, 아래 코드에서는 기본값이 적용되지 않습니다.
function greetUser(name = "User") {
console.log(name);
}
greetUser(""); // ""
greetUser(null); // null
greetUser(false); // false
greetUser(0); // 0이 점이 || 방식과 가장 큰 차이입니다.
6. 상황별 추천 방식
| 상황 | 추천 방식 |
|---|---|
"", 0, false도 비어 있는 값으로 보고 기본값을 쓰고 싶을 때 |
|| |
null, undefined일 때만 기본값을 쓰고 싶을 때 |
?? |
| 함수 인자가 생략되었을 때만 기본값을 쓰고 싶을 때 | 기본 매개변수 |
| 빈 문자열, 공백 문자열, 타입 검증까지 직접 처리하고 싶을 때 | 명시적 조건문 |
7. 더 명확한 greetUser 예제
7-1. 빈 문자열도 기본 이름으로 처리하고 싶은 경우
function greetUser(name, greeting) {
const displayName = name || "User";
const displayGreeting = greeting || "Hello";
console.log(`${displayGreeting}, ${displayName}!`);
}
greetUser("Alice", "Hi"); // "Hi, Alice!"
greetUser("", "Hi"); // "Hi, User!"
greetUser("Alice"); // "Hello, Alice!"이 코드는 빈 문자열도 “입력 없음”으로 봅니다.
7-2. 빈 문자열은 유지하고, null 또는 undefined만 기본값 처리하는 경우
function greetUser(name, greeting) {
const displayName = name ?? "User";
const displayGreeting = greeting ?? "Hello";
console.log(`${displayGreeting}, ${displayName}!`);
}
greetUser("Alice", "Hi"); // "Hi, Alice!"
greetUser("", "Hi"); // "Hi, !"
greetUser("Alice"); // "Hello, Alice!"
greetUser(null, "Hi"); // "Hi, User!"이 코드는 빈 문자열 ""을 유효한 값으로 봅니다.
7-3. 공백 문자열까지 검사하는 실무형 예제
function greetUser(name, greeting) {
const displayName =
typeof name === "string" && name.trim() !== ""
? name.trim()
: "User";
const displayGreeting =
typeof greeting === "string" && greeting.trim() !== ""
? greeting.trim()
: "Hello";
console.log(`${displayGreeting}, ${displayName}!`);
}
greetUser("Alice", "Hi"); // "Hi, Alice!"
greetUser("", "Hi"); // "Hi, User!"
greetUser(" ", "Hi"); // "Hi, User!"
greetUser(" Alice ", "Hi"); // "Hi, Alice!"
greetUser("Alice"); // "Hello, Alice!"사용자 입력값을 처리하는 경우에는 이처럼 trim()까지 함께 고려하는 것이 더 안전합니다.
8. 유체 이름 변환 예제
다음 코드는 입력된 유체 이름을 소문자로 바꾼 뒤, 별칭을 표준 이름으로 변환하는 예제입니다.
원래 코드입니다.
function extractfluidstring(inputString) {
let FluidName = inputString.toLowerCase();
// Check for alternative names. Use lower case for all fluid names below.
const fluidNameMap = {
carbondioxide: "co2",
carbonmonoxide: "co",
c1: "methane",
c2: "ethane",
c3: "propane",
ic4: "isobutane",
c4: "butane",
};
FluidName = fluidNameMap[FluidName] || FluidName;
}이 코드의 핵심 아이디어는 좋습니다.
하지만 실무에서는 다음 부분을 보완하는 것이 좋습니다.
- 함수명은 일반적으로 camelCase로 작성합니다.
- 변수명도
FluidName보다fluidName이 JavaScript 관례에 더 맞습니다. inputString이null또는undefined이면toLowerCase()에서 오류가 발생합니다."Carbon Dioxide","carbon-dioxide","carbon_dioxide"같은 입력도 처리하려면 정규화가 필요합니다.- 함수가 변환한 값을
return해야 재사용할 수 있습니다.
9. 개선된 유체 이름 변환 함수
function normalizeFluidInput(inputString) {
return String(inputString ?? "")
.trim()
.toLowerCase()
.replace(/[\s_-]+/g, "");
}
function extractFluidString(inputString) {
const fluidName = normalizeFluidInput(inputString);
const fluidNameMap = {
carbondioxide: "co2",
carbonmonoxide: "co",
c1: "methane",
c2: "ethane",
c3: "propane",
ic4: "isobutane",
c4: "butane",
};
return fluidNameMap[fluidName] ?? fluidName;
}사용 예제입니다.
console.log(extractFluidString("CarbonDioxide")); // "co2"
console.log(extractFluidString("carbon dioxide")); // "co2"
console.log(extractFluidString("carbon-dioxide")); // "co2"
console.log(extractFluidString("carbon_monoxide")); // "co"
console.log(extractFluidString("C1")); // "methane"
console.log(extractFluidString("c2")); // "ethane"
console.log(extractFluidString("ic4")); // "isobutane"
console.log(extractFluidString("water")); // "water"
console.log(extractFluidString(null)); // ""
console.log(extractFluidString(undefined)); // ""여기서 inputString ?? ""는 입력값이 null 또는 undefined일 때만 빈 문자열로 바꿉니다.
그리고 마지막 줄의 fluidNameMap[fluidName] ?? fluidName은 매핑된 값이 있으면 그 값을 반환하고, 없으면 원래 정규화된 이름을 반환합니다.
10. || 대신 ??를 사용한 이유
아래 코드도 현재 예제에서는 동작합니다.
return fluidNameMap[fluidName] || fluidName;매핑 값이 모두 "co2", "methane"처럼 truthy 문자열이기 때문입니다.
하지만 나중에 매핑 값으로 빈 문자열 "", 0, false 같은 값이 들어갈 가능성이 있다면 ||는 의도치 않게 원래 값을 반환할 수 있습니다.
const map = {
unknown: "",
};
const key = "unknown";
console.log(map[key] || key); // "unknown"
console.log(map[key] ?? key); // ""따라서 객체 매핑 결과를 확인할 때는 ??가 더 의도를 명확하게 표현하는 경우가 많습니다.
11. 엄격한 검증이 필요한 경우
입력값이 비어 있으면 빈 문자열을 반환하는 대신 오류를 발생시키고 싶을 수도 있습니다.
function extractFluidStringStrict(inputString) {
const fluidName = normalizeFluidInput(inputString);
if (!fluidName) {
throw new Error("fluid name is required");
}
const fluidNameMap = {
carbondioxide: "co2",
carbonmonoxide: "co",
c1: "methane",
c2: "ethane",
c3: "propane",
ic4: "isobutane",
c4: "butane",
};
return fluidNameMap[fluidName] ?? fluidName;
}사용 예제입니다.
console.log(extractFluidStringStrict("CarbonDioxide")); // "co2"
console.log(extractFluidStringStrict("C1")); // "methane"
console.log(extractFluidStringStrict(""));
// Error: fluid name is required입력값이 반드시 필요하다면 이처럼 명시적으로 오류를 발생시키는 편이 디버깅에 유리합니다.
12. 객체 옵션 기본값 예제
함수 옵션을 처리할 때도 기본값 설정은 자주 사용됩니다.
function createUser(options = {}) {
const name = options.name ?? "Guest";
const age = options.age ?? 0;
const isAdmin = options.isAdmin ?? false;
return {
name,
age,
isAdmin,
};
}
console.log(createUser());
// { name: "Guest", age: 0, isAdmin: false }
console.log(createUser({ name: "Alice", age: 0, isAdmin: false }));
// { name: "Alice", age: 0, isAdmin: false }여기서 ??를 사용하면 age: 0, isAdmin: false 같은 값을 정상적인 값으로 유지할 수 있습니다.
만약 ||를 사용했다면 0과 false가 기본값으로 덮어써질 수 있습니다.
13. ??= 연산자 활용하기
객체에 기본값을 직접 채워 넣고 싶다면 ??= 연산자를 사용할 수도 있습니다.
??=는 왼쪽 값이 null 또는 undefined일 때만 오른쪽 값을 할당합니다. (MDN Web Docs)
function applyDefaultOptions(options) {
options.name ??= "Guest";
options.age ??= 0;
options.isAdmin ??= false;
return options;
}
console.log(applyDefaultOptions({ name: "Alice" }));
// { name: "Alice", age: 0, isAdmin: false }
console.log(applyDefaultOptions({ age: 0, isAdmin: false }));
// { age: 0, isAdmin: false, name: "Guest" }||=도 있지만, 이 연산자는 왼쪽 값이 falsy일 때 할당합니다. 따라서 0, false, ""를 보존해야 하는 경우에는 ??=가 더 안전합니다. (GitHub)
14. 정리
사용자 입력처럼 빈 문자열도 잘못된 값으로 보고 싶다면 || 또는 명시적 조건문을 사용할 수 있습니다.
반대로 숫자 0, 불리언 false, 빈 문자열 ""도 정상적인 값으로 인정해야 한다면 ??를 사용하는 것이 더 안전합니다.
0 댓글