ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JS - GOOD/BAD CODE
    JavaScript 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
Designed by Tistory.