-
JS - GOOD/BAD CODEJavaScript 2021. 7. 18. 10:22
const/let
- const 는 재할당이 불가능하기에 다른 개발자나 이후 본인이 다시 코드를 볼때 변수 선언 후 변경이 생기지 않는 다는 것을 확신할 수 있기 때문에 값을 변경하는 경우가 아니라면 무조건 const 를 사용해라(배열, 객체의 경우 배열 항목, 객체 키,값은 변경할 수 있음)
배열 메서드 활용
// 배열의 경우 빈 배열로 선언하여 loop 하는 것보다 filter 등 배열 메서드를 활용해라 // 배열 내의 일정 조건으로 다시 배열을 만들때 const items = [ { name: "car", active: true, }, { name: "bus", active: false, }, ]; // Bad const activeItems_ = []; for (let i = 0; i < items.length; i++) { if (items[i].active) { activeItems_.push(items[i]); } } // Good // 1. 조작(mutation)을 피할수 있다. // 2. 코드가 줄어든다. // 3. 변수 선언을 미리 하지 않아도 됨 const activeItems = items.filter((item) => item.active); console.log(activeItems_, activeItems); // 배열의 매서드 find const dogPair = [ ["name", "Don"], ["color", "black"], ]; function getName(dogPair) { return dogPair.find((attribute) => attribute[0] === "name")[1]; } console.log(getName(dogPair)); // Don // 배열의 매서드 include const sections = ["contact", "shipping"]; // Good function displayShipping(sections) { return sections.includes("shipping"); } // Bad // 존재하지 않을 경우 -1, 첫 항목의 경우 인덱스가 0이기에 fasly 값으로 좋지 못함 function displayShipping(sections) { return sections.indexOf("shipping") > -1; } // 배열의 매서드 map const band = [ { name: "corbett", instrument: "guitar", }, { name: "evan", instrument: "guitar", }, { name: "sean", instrument: "bass", }, { name: "brett", instrument: "drums", }, ]; // map은 콜백함수를 받기때문에 함수를 인자로 넣거나 화살표 익명함수 function getInstruments() { function getInstrument(member) { return member.instrument; } const instruments = band.map(getInstrument); return instruments; } function getInstruments2() { const instruments = band.map((member) => member.instrument); return instruments; } // find const instructors = [ { name: "Jim", libraries: ["MERIT"], }, { name: "Sarah", libraries: ["Memorial", "SLIS"], }, { name: "Eliot", libraries: ["College Library"], }, ]; function findMemorialInstructor(instructors) { const librarian = instructors.find((instructor) => { return instructor.libraries.includes("Memorial"); }); return librarian; } function findAnyInstructor(instructors) { const findByLibrary = (library) => (instructor) => { return instructor.libraries.includes(library); }; const librarian = instructors.find(findByLibrary("MERIT")); // find 메서드에 콜백함수로 findByLibrary 보내줌 - 커링 기법 return librarian; } console.log(findMemorialInstructor(instructors)); console.log(findAnyInstructor(instructors)); // chain const students = [ { focus: "nagarjuna", }, { focus: "logic", }, { focus: "consciousness", }, { focus: "", }, { focus: "logic", }, ]; const focuses = students .map((student) => student.focus) .filter((focus) => focus) .reduce((focuses, focus) => { const count = focuses.get(focus) || 0; focuses.set(focus, count + 1); return focuses; }, new Map()); const formattedFocus = [...focuses] .sort() .map(([name, count]) => `${name}: ${count}`); console.log(formattedFocus); // ["consciousness: 1", "logic: 2", "nagarjuna: 1"] const sailors = [ { name: "yi hong", active: true, email: "yh@yhproductions.io", }, { name: "alex", active: true, email: "", }, { name: "nathan", active: false, email: "", }, ]; function sendActiveMemberEmail(sailors, sendEmail) { sailors .filter((sailor) => sailor.active) .map((sailor) => sailor.email || `${sailor.name}@wiscsail.io`) .forEach((sailor) => sendEmail(sailor)); } const sendEmail = (email) => { console.log(`Eamil sent to ${email}`); }; console.log(sendActiveMemberEmail(sailors, sendEmail)); // Eamil sent to yh@yhproductions.io // Eamil sent to alex@wiscsail.io펼침 연산자
// 기존의 team 변수를 참조하는 것이 아닌 새롭게 할당하기 위해 펼침 연산자 사용 const team = ["Joe", "Dyan", "Bea", "Theo"]; // Good function alphabetizeTeam(team) { return [...team].sort(); } const sortedTeam = alphabetizeTeam(team); console.log(team, sortedTeam); // ["Joe", "Dyan", "Bea", "Theo"] (4) ["Bea", "Dyan", "Joe", "Theo"] // Bad const team_ = ["Joe", "Dyan", "Bea", "Theo"]; function alphabetizeTeam_(team) { return team.sort(); } const sortedTeam_ = alphabetizeTeam_(team_); console.log(team_, sortedTeam_); // ["Bea", "Dyan", "Joe", "Theo"] (4) ["Bea", "Dyan", "Joe", "Theo"] // 펼침 연산자 2 const book = ["Reasons and Persons", "Derek Parfit", 19.99]; function formatBook(title, author, price) { return `${title} by ${author} $${price}`; } // bad formatBook(book[0], book[1], book[2]); // good formatBook(...book); // 배열에서 항목 제거 function removeItem(items, removable) { if (items.includes(removable)) { const index = items.indexOf(removable); return [...items.slice(0, index), ...items.slice(index + 1)]; } return items; }객체 할당
const defaults_ = { author: "", title: "", year: 2017, rating: null }; const defaults = { author: "", title: "", year: 2017, rating: null }; const textbook = { author: "Joe Morgan", title: "Simplifying JavaScript", }; // bad defaults 값을 변경함 const updated_ = Object.assign(defaults_, textbook); console.log(defaults_, updated_); // {author: "Joe Morgan", title: "Simplifying JavaScript", year: 2017, rating: null} // {author: "Joe Morgan", title: "Simplifying JavaScript", year: 2017, rating: null} // good const updated = Object.assign({}, defaults, textbook); console.log(defaults, updated); // {author: "", title: "", year: 2017, rating: null} // {author: "Joe Morgan", title: "Simplifying JavaScript", year: 2017, rating: null} // 객체 깊은 복사 const defaultEmployee = { name: { first: "", last: "", }, years: 0, }; // bad const employee_ = Object.assign({}, defaultEmployee); employee_.name.first = "Joe"; defaultEmployee; // 객체 안의 name 객체의 경우 깊은 복사가 안되고 참조되어 원래 데이터의 값이 변경됨 // good const employee2 = Object.assign({}, defaultEmployee, { name: Object.assign({}, defaultEmployee.name), });객체보다는 Map 활용
- 키-값 쌍이 자주 추가, 삭제되는 경우
- 키가 문자열이 아닌 경우
- 아래의 기능들로 Map 에 항상 메서드를 사용하며, 언어 수준의 연산자를 섞지 않음
- 객체처럼 delete, 재할당 하지 않으며, clear() 메서드를 사용할 수 있어 새로운 인스턴스 생성할 필요 없음
- 단점 : 정렬 메서드는 없음
- 펼침 연산자로 [...mapData] = [[key1, value1], [key2, value2]] 의 배열로 변경 가능
const petFilters = new Map(); function addFilters(filters, key, value) { filters.set(key, value); } function deleteFilters(filters, key) { filters.delete(key); } function clearFilters(filters) { filters.clear(); } // Map의 업데이트 function applyDefaults(map, defaults) { return new Map([...defaults, ...map]); } // 위와 같은 기능의 객체 // 단점 : 객체의 키 값은 숫자도 문자열로 변경되어 저장됨 // 삭제 시 결국 변수를 재 할당하는 것 function addFilters_(filters, key, value) { filters[key] = value; } function deleteFilters_(filters, key) { delete filters[key]; } function clearFilters_(filters) { filters = {}; return filters; }Set - 중복된 값은 추가하지 않는 배열
function getUniqueColors(dogs) { const unique = new Set(); for (const dog of dogs) { unique.add(dog.color); } return [...unique]; }조건문과 삼항 연산자
function configureTimePermissions(title) { const permissions = title === "manager" ? ["time", "pay"] : ["time"]; return permissions; } // 자바스크립트에서 거짓값 const faslyList = [false, null, 0, NaN, "", undefined]; function getImage_(userConfig) { // userConfig.images = 객체에 키 값이 존재하는지 // userConfig.images.length > 0 = 빈 배열이 아닌지 체크해야 TypeError 방지 if (userConfig.images && userConfig.images.length > 0) { return userConfig.images[0]; } return "default.png"; } // better function getImage(userConfig) { const images = userConfig.images; return images && images.length ? images[0] : "default.png"; }화살표 함수와 콜백함수
function applyCustomGreeting(name, callback) { return callback(capitalize(name)); } function greetWithExcitement() { const greeting = applyCustomGreeting("joe", (name) => `Hi, ${name}!`); return greeting; }반복문
// 반복분 const firms1 = { 10: "Ivie Group", 23: "Soundscaping Source", 31: "Big 6", }; function checkConflicts1(firms, isAvailable) { for (const id in firms) { if (!isAvailable(parseInt(id, 10))) { return `${firms[id]} is not available`; } } return "All firms are available"; } const firms2 = new Map() .set(10, "Ivie Group") .set(23, "Soundscaping Source") .set(31, "Big 6"); function checkConflicts2(firms, isAvailable) { for (const firm of firms) { const [id, name] = firm; // key, value 같이 받음 if (!isAvailable(id)) { return `${name} is not available`; } } return "All firms are available"; }함수의 매개변수 해체 할당
function determineCityAndState([latitude, longitude]) { const region = { city: "Hobbs", county: "Lea", state: { name: "New Mexico", abbreviation: "NM", }, }; return region; } // 매개 변수 객체 해체 할당 function setRegion({ location, ...details }) { const { city, state } = determineCityAndState(location); return { city, state: state.abbreviation, ...details, }; } // 매개 변수의 default 값 // Bad function convertWeight(weight, ounces, roundTo) { const oz = ounces / 16 || 0; const total = weight + oz; const conversion = total / 2.2; const round = roundTo === undefined ? 2 : roundTo; return roundToDecimalPlace(conversion, round); } // Good function convertWeight(weight, ounces = 0, roundTo = 2) { const total = weight + ounces / 16; const conversion = total / 2.2; return roundToDecimalPlace(conversion, roundTo); } // arguments - 배열 function getArguments(...args) { return args; } console.log(getArguments("Bloomsday", "June 16")); // ["Bloomsday", "June 16"] function validateCharacterCount(max, ...items) { // ... 없이 items으로 하면 매개 변수 그대로 적용되어 배열이 아닌 경우 items.every 에서 에러 발생 return items.every((item) => item.length < max); } validateCharacterCount(10, "wvoquie"); // ...items 로 배열로 할당됨 // true validateCharacterCount(10, ...["wvoquie"]); // true validateCharacterCount(10, "Hobbs", "Eagles"); // true함수
// 해체 할당 const landscape = { title: "Landscape", photographer: "Nathan", equipment: "Canon", format: "digital", src: "/landscape-nm.jpg", location: [32.7122222, -103.1405556], }; const anonymous = { title: "Kids", equipment: "Nikon", src: "/garden.jpg", location: [38.9675338, -95.2614205], }; // Bad function displayPhoto_(photo) { const title = photo.title; const photographer = photo.photographer || "Anonymous"; const location = photo.location; const url = photo.src; const copy = { ...photo }; delete copy.title; delete copy.photographer; delete copy.location; delete copy.src; const additional = Object.keys(copy).map((key) => `${key}: ${copy[key]}`); return ` <img alt="Photo of ${title} by ${photographer}" src="${url}" /> <div>${title}</div> <div>${photographer}</div> <div>Latitude: ${location[0]} </div> <div>Longitude: ${location[1]} </div> <div>${additional.join(" <br/> ")}</div> `; } // Good ( 해체 할당은 let으로 변수를 할당 - 변경 가능) function displayPhoto({ title, photographer = "Anonymous", location: [latitude, longitude], src: url, // 키 변경 src -> url ...other }) { const additional = Object.keys(other).map((key) => `${key}: ${other[key]}`); return ` <img alt="Photo of ${title} by ${photographer}" src="${url}" /> <div>${title}</div> <div>${photographer}</div> <div>Latitude: ${latitude} </div> <div>Longitude: ${longitude} </div> <div>${additional.join(" <br/> ")}</div> `; }커링
링은 함수 하나가 n개의 인자를 받는 과정을 n개의 함수로 각각의 인자를 받도록 하고, 부분적으로 적용된 함수를 체인으로 계속 생성해 결과적으로 값을 처리
const discounter = (discount) => (price) => price * (1 - discount); const tenPercentOff = discounter(0.1); tenPercentOff(100); // 90 const dogs = [ { name: "max", weight: 10, breed: "boston terrier", state: "wisconsin", color: "black", }, { name: "don", weight: 90, breed: "labrador", state: "kansas", color: "black", }, { name: "shadow", weight: 40, breed: "labrador", state: "wisconsin", color: "chocolate", }, ]; function getDogNames(dogs, filterFunc) { return dogs.filter(filterFunc).map((dog) => dog.name); } const identity = (field) => (value) => (dog) => dog[field] === value; const colorCheck = identity("color"); const stateCheck = identity("state"); console.log(getDogNames(dogs, colorCheck("chocolate"))); // ['shadow'] console.log(getDogNames(dogs, stateCheck("kansas"))); // ['don'] const building = { hours: "8 a.m. - 8 p.m.", address: "Jayhawk Blvd", }; const manager = { name: "Augusto", phone: "555-555-5555", }; const program = { name: "Presenting Research", room: "415", hours: "3 - 6", }; const exhibit = { name: "Emerging Scholarship", contact: "Dyan", }; // END:info // START:func function mergeProgramInformation(building, manager) { const { hours, address } = building; const { name, phone } = manager; const defaults = { hours, address, contact: name, phone, }; return (program) => { return { ...defaults, ...program }; }; } const programInfo = mergeProgramInformation(building, manager)(program); const exhibitInfo = mergeProgramInformation(building, manager)(exhibit); const birds = ["meadowlark", "robin", "roadrunner"]; const zip = (...left) => (...right) => { return left.map((item, i) => [item, right[i]]); }; console.log(zip("kansas", "wisconsin", "new mexico")(...birds)); // [ // ['kansas', 'meadowlark'], // ['wisconsin', 'robin'], // ['new mexico', 'roadrunner'] // ]'JavaScript' 카테고리의 다른 글
NodeJS - Express, file structure (0) 2022.02.19 Docker - Express(TS) - Config(Prod,dev,test) (0) 2022.01.30 빌트인 객체, 래퍼 객체 (0) 2021.12.17 변수(var, let, const) + feat.메모리 (0) 2021.12.16 자바스크립트 this (0) 2021.12.16