본문 바로가기
Javascript/YDKJS

YDKJS (유돈노JS) part1 부록 A,B

by ginny. 2024. 9. 20.

값 VS 참조

값의 타입에 따라 값 자체를 넘겨줄지, 값의 참조를 넘겨줄지 결정된다. > JS의 작동방식. 바꿀수없다

원시타입=값이 복사되어 전달됨. var myName="Amy" var yourName = myName (myName을 바꿔도 yourName은 안바뀜)

객체타입=값의 참조(주소)를 복사해 전달. 여러 변수가 하나의 공유값을 가리킴. 공유값을 수정하면 참조하는 모든변수가 바뀜

다양한 형태의 함수

익명함수표현식

var nonameF = function () {...} > 이때는 익명함수더라도 자체적으로 이름을 추론하기 때문에 nonameF.name = nonameF 그러나 인수로 전달시에는  name은 빈문자열, anonymous function으로 콘솔찍힘.

기명함수표현식

var nameF = function exName() {..} > 런타임시 식별자nameF와 연관. 직접 지정한 함수이름exName이 우선순위.

둘중 어떤 방식을 쓸까? 대부분이 익명함수표현식 사용함. 짧고 일반적이라. (필자왈-기명함수를 선호) 프로그램내 함수는 목적이 있어야하고, 목적을 설명하는 이름을 부여해야함. 그러면 굳이 이름을 추론할 필요없다.

여러가지 함수선언방식을 충분히 숙지하고 연습하자

제너레이터 - function *two() {}

async함수- async function three(){}

async제너레이터 함수 - async function *four(){}

IIFE(즉시실행함수) 표현식 - (function(){..})()

비동기 IIFE - (async function() {})()

화살표함수표현식 - var f =(x)=>x*2

화살표함수는 익명이다.(문법적으로) 특별한목적을 가진 함수(this가 참조하는 렉시컬환경 핸들링하기)

클래스메서드는 쉼표가 없다, 객체메서드는 쉼표로 구분함.

강제 조건부 비교

비교전 무조건 강제변환이 일어난다. Boolean() 타입으로.

var x = "안녕하세요";
if (x == true) {
  console.log("괄호실행"); //실행되지 않음!! Boolean(x)는 true인데 왜?
}

(+추가) == 연산자는 양쪽 값을 비교하기 전에 암묵적인 형 변환을 수행함. x를 숫자로 변환하려고 시도하지만 NaN. 따라서 NaN!==true이므로 실행안됨.,

해결책은 Boolean(x)나 if (x)를 사용하면 됩니다. 이렇게 하면 x가 빈 문자열이 아닌 이상 true로 평가되어 if문이 실행됩니다.

프로토타입 클래스

프로토타입을 사용한 상속, 모든함수는 기본적으로 prototype프로퍼티를 가지고 빈 객체를 참조함. 

(프로토타입 프로퍼티 != 함수의 프로토타입과 다름)

프로토타입 프로퍼티는 new로 호출해 객체를 만들때, 새롭게 만든 객체의 프로토타입을 설정할수 있게해줌

프로토타입 클래스패턴 VS ES6 클래스 매커니즘? 클래스지향 디자인패턴은 ES6 클래스가 적합.

 

B1.비교 연습하기

처음시도한 방법 : 냅다 문자열비교하기 startHour >= dayStart && startHour <= dayEnd 

문제 : 07:30 == 7:30 비교시 false 나옴..

수정한 방법 : 문자열을 숫자로 바꿔서 비교하자.

(방법1) Number(startHour) 로 변환하기 ...는 NaN이 나와서 안됨 

(방법2) 콜론 기준 split해서 각각 hour, minute을 Number로 변환하기. 

최종코드

 
const dayStart = "07:30"; // 근무시작시간
const dayEnd = "17:45"; //근무종료시간
//console.log(5 + dayEnd); //517:45 문자열로 바꿔버림
//console.log(Number(dayEnd)); //NaN

//회의가 근무시간내 이뤄지면 true, 아니면 false
function scheduleMeeting(startTime, duartionMinutes) {
  let [dayStartHour, dayStartMinute] = dayStart.split(":").map(Number);
  let [dayEndHour, dayEndMinute] = dayEnd.split(":").map(Number);
  let [startHour, startMinute] = startTime.split(":").map(Number);

  if (
    (startHour >= dayStartHour && startMinute >= dayStartMinute) ||
    (dayStartHour < startHour &&
      startHour <= dayEndHour &&
      startMinute <= dayEndMinute) //여기서 dayStartHour < startHour 조건을 넣지않으면 07:00 을 테스트했을때 true나옴!
  ) {
    //시작시간이 근무시간 중이면, 끝나는 시간도 고려해야함
    let endHour = startHour;
    let endMinute = startMinute + duartionMinutes; //끝나는 시간 계산중
    if (endMinute >= 60) {
      endHour += 1;
      endMinute = endMinute - 60;
    }
    if (endHour < 17 || (endHour <= 17 && endMinute <= 45)) {
      //회의끝난시간이 퇴근전이면 true
      return true;
    } else return false; //아니면 false
  }
  // 시작시간이 근무시간 중이 아니면 false
  return false;
}

console.log(scheduleMeeting("7:00", 15));
console.log(scheduleMeeting("07:15", 30));
console.log(scheduleMeeting("7:30", 30));
console.log(scheduleMeeting("11:30", 60));
console.log(scheduleMeeting("17:00", 45));
console.log(scheduleMeeting("17:30", 30));
console.log(scheduleMeeting("18:00", 15));

 

B2.클로저 연습하기

function range(start, end) {
  if (end == undefined) {
    return function (end) {
      let ret = [];
      for (let i = start; i <= end; i++) {
        ret.push(i);
      }
      return ret;
    };
  }
  let ret = [];
  for (let i = start; i <= end; i++) {
    ret.push(i);
  }
  return ret;
}

console.log(range(3, 3));
console.log(range(3, 8));
console.log(range(3, 0));
var start3 = range(3);
var start4 = range(4);
console.log(start3(3));
console.log(start3(8));
console.log(start3(0));
console.log(start4(6));

 

B3.프로토타입 연습하기

1e9 은 무엇인가? 정수형으로 10억

Math.floor 내림, Math.trunc 버림. 

 

  • Math.trunc(): 소수점 이하를 무조건 버림.
  • Math.floor(): 소수점을 버리고 작은 쪽으로 내림.

 

function randMax(max) {
  return Math.trunc(1e9 * Math.random()) % max; //0~max-1 까지의 무작위 수 생성
}

var reel = {
  //reel객체, reel동작을 정의
  symbols: [
    //symbols.length = 8
    "\u2660", //스페이드
    "\u2665", //하트
    "\u2666", //다이아
    "\u2663", //클로버
    "\u263A", //스마일
    "\u2605", //별
    "\u2764", //달**이모지깨져서 바꿈..원래 \u1F319
    "\u2600", //해
  ],
  spin() {
    if (this.position == null) {
      //맨처음에만 실행됨, position을 0~6까지로 설정함 (**수정필요)
      this.position = randMax(this.symbols.length - 1); //**여기가 this.symbols.length여야함 그래야 0~7까지나옴
    } //두번째부터는 아래코드 실행됨
    this.position = (this.position + 100 + randMax(100)) % this.symbols.length;
  },
  display() {
    if (this.position == null) {
      // position을 0~6까지로 설정함 (**수정필요)
      this.position = randMax(this.symbols.length - 1);
    }
    return this.symbols[this.position]; //position에 해당하는 심볼기호를 리턴함
  },
};

var slotMachine = {
  reels: [Object.create(reel), Object.create(reel), Object.create(reel)], //코드작성
  spin() {
    this.reels.forEach(function spinReel(reel) {
      reel.spin();
    });
  },
  display() {
    // this.reels.forEach((reel) => console.log(reel.display()));
    //reels는 3개의 reel(객체)이 저장된 배열, 각position을 설정해주기위해 spin을 했음.
    var lines = [];

    for (let linePos = -1; linePos <= 1; linePos++) {
      //linePos=-1 : 현재릴의 앞의심볼을 가리킴, linePos=1 : 현재릴의 다음심볼을 가리킴

      let line = this.reels.map(function getSlot(reel) {
        var slot = Object.create(reel);
        slot.position =
          (reel.symbols.length + reel.position + linePos) % reel.symbols.length;
        return slot.display();
      });
      lines.push(line.join(" | ")); //각 라인별로 출력할 심볼3개를 한줄로 만들어 lines에 추가 (line은 '❤ | ★ | ♦' 형태임)
    }
    return lines.join("\n"); //lines배열에 저장된 문자열 총3개를 엔터로 구분해 출력
  },
};

slotMachine.spin();
console.log(slotMachine.display());

댓글