Codestates SEB FE 42기/정리노트

S1 unit10 | koans 문제로 알게 된 것들

2realzoo 2022. 11. 11. 08:08

📌 test 작성 방법

test를 위해서 koans은 두가지 모듈을 사용하고 있는데, 바로 mocha와 chai이다.

이때 테스트하는 값과 기대값을 비교하기 위해 expect() 함수를 사용하게 된다.

expect(true).to.be.true // 통과
expect(테스트하는 값).기대하는 조건

이런 형태로 사용하게 되는데 여기서 기대하는 조건에 해당하는 것을 matcher함수라고 부른다.

chai는 matcher를 다양한 language chains과 assertions으로 만드는데,[여기](http:// https://www.chaijs.com/api/bdd/#method\_not)에%EC%97%90) 다양한 체인과 assertion들이 소개되어 있다.

koans에서는 to.be , to. 체인만 사용했다.

to.be에는 boolean으로 판별하는 true, false 가 오기도 하고

to. 에는 equal()이 오기도 한다.
equal은 두 값 A와 B가 타입까지 같은지 엄격하게 검사한다. (strick equality, ===)

반대로 비교연산자 ==는 두 값의 일치 여부를 느슨하게 검사한다.(loose equality)
예를 들어, 연산자가 들어가는 test에서는

expect(1+1 == 2 ).to.be.true; // true
expect(1+1 == '2').to.be.true; // true

문자열과 숫자를 같다고 하고 있다. 이 외에도 falsy한 값을 false라고 하거나
비어있는 배열과 비어있는 문자열을 같다고 하기도 한다... 역시 ===만 사용하는 게 훨씬 마음 편하다.

📌 다양한 메소드

koans에서 출몰한 다양한 메소드를 소개해보겠다.

  • Object.toString() : object를 문자열로 변환함. 기본적으로 객체가 문자열로 참조될 것 같을 때 자동으로 호출됨. 🔗
  • Object.assign(target, source) : target에 iterable한 source를 복사한 후 target을 반환한다. (얕은 복사) 🔗
  • Array.from(arraylike, [mapFn [, thisArg] ]) : iterable한 arraylike(유사 객체, 반복가능 배열)를 복사하여 mapFn함수를 거친 새로운 array를 만듦. mapFn부터는 생략 가능함. thisArg는 mapFn 실행 시의 this 값이다. 🔗
  • array.slice(start , end) : start 포함된 end전까지의 새 배열을 반환한다.
    • start가 end보다 크가니 같으면 빈 배열을 반환한다.
    • end가 array.length보다 크면 끝까지 복사한다.(slice는 쓸 때마다 헷갈리는 것 같다😥)
    • console.log(arr.slice(5, 1)); //[]
  • String.repeat(n) : 문자열 주어진 횟수만큼 반복 🔗

📌 default parameter (기본값 매개변수)

: 값이 없거나 undefined인 변수가 들어와도 기본값으로 함수가 처리된다.🔗

function multiply(a, b = 1) {
  return a * b;
}
console.log(multiply(5)); // 5
console.log(multiply()); // 1

 

📌 스코프와 클로저

스코프 : 변수 접근 규칙 🔗

  1.  안쪽에서 바깥쪽 접근 가능, 바깥에서 안쪽 불가능
  2.  스코프 중첩 가능

전역 스코프 (global scope) : 가장 바깥쪽 스코프

지역 스코프 (local scope) : 안쪽 스코프

 

함수 스코프 :  함수로 만들어진 스코프 (함수 선언식, 함수 표현식)

블록 스코프 :  블록으로 만들어진 스코프  (화살표 함수 등)

 

렉시컬 스코프 : 스코프가 생길 때의 어휘적 환경

var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // ?
bar(); // ?

함수가 호출될 때가 아니라 함수가 선언될 때 상위 스코프가 결정된다.

bar()는 선언 전에 호출되고 있지만 호이스팅으로 인해 최상위 스코프에 선언만 옮겨졌다.

따라서 선언 전에 호출을 해도 작동이 가능하다.

또한 bar() 선언에서의 x는 전역 변수인 x = 1 가 사용되므로 bar는 무조건 1을 반환하게 된다.

따라서 둘 다 1을 반환한다.

 

 

var : 함수 스코프만 유효, 화살표 함수 블록 스코프 제외한 블록 스코프 무시 

let, const : 함수, 블록 스코프 유효

 

클로저 : 함수와 그 함수의 렉시컬 환경(스코프) 의 조합 🔗

함수 안에 함수가 있고 그 바깥쪽에서 정의된 것을 안쪽에서 사용할 때,

바깥쪽 함수가 끝나도 안쪽 함수에선 그 변수가 남아있다.

 

클로저 은닉화 : 클로저를 이용해 바깥에서는 클로저 내의 변수에 접근하지 못하게 할 수 있다.

📌 참조자료형과 스코프

참조자료형인 전역변수를 다른 변수에 할당하면 reference가 할당된 것이다.

const arr = ['zero', 'one', 'two', 'three', 'four', 'five'];

    function passedByReference(refArr) {
      refArr[1] = 'changed in function';
    }
    passedByReference(arr);
    expect(arr[1]).to.equal('changed in function');

헷갈렸던 점 : reArr라는 새로운 변수가 선언된 게 아닌가?
=> 선언됐더라도 arr의 reference를 할당했기 때문에 arr[1]이 바뀜.

📌 object.length

:object는 length 속성이 없다.

그러면 object.length는 뭐가 나올까?

바로 undefined이다.

Object.keys(obj)를 사용하면 키 부분의 새 array를 얻을 수 있고, length를 구할 수 있다. 🔗

📌 this

: 호출당시 자신의 렉시컬 스코프에 해당하는 객체부분을 가리킴

  • 객체에서 본인의 키 값을 참조하고 싶을 때

내가 생각하기로는 각각의 키 값 자체가 같은 단계에서 다른 지역변수를 가지고 있기 때문에 다른 키에서는 참조가 안되는 것 같다. 아예 하위 스코프인 megalomaniac객체에서 그 키를 불러내는 것은 가능한 거로 보면...

🔗

📌 ...rest paremeter

: 함수의 전달인자로 사용되며 정해지지 않은 인자를 받을 수 있다. 🔗

  • 여러 개의 전달인자를 넣으면 하나의 배열로 반환된다.
function getAllParamsByRestParameter(...args) {
      return args;
    }
const restParams = getAllParamsByRestParameter('first', 'second', 'third');
expect(restParams).to.deep.equal(['first', 'second', 'third']);
  • rest parameter를 함수 전달인자로 사용하고 실제 함수 작동할 때 전달인자에 ...args 넣지 않으면 빈 배열 반환
function getAllParams(required1, required2, ...args) {
    return [required1, required2, args];
  }
expect(getAllParams(123)).to.deep.equal([123, undefined, []]);

rest parameter랑 spread랑 조금 헷갈리는데 이 부분은 rest는 함수에서 나머지 인자를 받는 역할,

spread는 아무데나 사용될 수 있으면서 펼치는 것! 으로 생각하면 될 것 같다.

spread로 처음에 정의해둔 변수를 함수 내로 가져와서 사용할 수도 있다.

📌 구조 분배 할당 구문

: 배열이나 객체의 속성을 해체하여 그 값을 개별 변수로 사용할 수 있게 만드는 구문
구문 사용 시 선언 필수 🔗

const array = ['code', 'states', 'im', 'course']  
const [first, second] = array    
expect(first).to.eql('code') //통과
const student = { name: '박해커', major: '물리학과' }
const { name } = student
expect(name).to.eql('박해커') //통과
const student = { name: '최초보', major: '물리학과' }
  const { name, ...args } = student

  expect(name).to.eql('최초보')
  expect(args).to.eql({major: '물리학과'})
})

마지막 코드블럭에서는 rest parameter를 함께 사용했다.

여기서 rest parameter는 object를 반환했다.

📌 객체 단축 문법 (shorthand)

const name = '김코딩'
const age = 28
const person = {
    name,
    age,
    level: 'Junior',
  }
expect(person).to.eql({
    name: '김코딩',
    age: 28,
    level: 'Junior',
  })

객체 내부에 전역변수를 그냥 써도 키 부분은 변수, 키 값 부분은 변수에 할당된 수로 자동 변환된다.

> (객체란 내부에 변수블럭이 있는 것처럼 작동하는 것 같다...)

 

📌 팩토리 함수 

: 함수가 객체를 반환하는 것

 

1. 기본적인 팩토리 함수

function createJelly() {
  return {
    type: 'jelly',
    colour: 'red'
    scoops: 3
  };
}

2. 파라미터를 받는 팩토리 함수 (기본 값 매개변수를 사용)

function createIceCream(flavour='Vanilla') {
  return {
    type: 'icecream',
    scoops: 3,
    flavour
  }
}

3. 팩토리 함수끼리 조합

function createDessert() {
  return {
    type: 'dessert',
    bowl: [
      createJelly(),
      createIceCream()
    ]
  };
}

위 두 팩토리함수를 조합하여 createDessert()라는 더 복잡한 팩토리 함수를 생성했다.

 

이외의 팩토리 함수는 아직 이해하기 어려워서 링크만 첨부! 🔗

📌 클로저 유즈 케이스

🔗자바스크립트에서 팩토리 함수란 무엇인가

🔗10 function factories

🔗namespacing