회고

복습(Koans, DOM)

Happy Programmer 2022. 5. 21. 22:47

1.koans를 복습하면서 보니 introduction에 나오는 단순한 문제들( 1+1 과 빈칸을 비교하는 문제 반복)을 대충 문제 푸는 방식 설명으로 이해하고 넘어갔는데 지금 다시 보면 테스트케이스를 작성하는 요령에 대해서 설명하는 것 같다.
예를 들어  expect(a === b).to.be.true; 에서 a와 b를 비교하는 방식과
    expect(1 + 1).to.equal(b); 와 같이 a,b를 할당하지 않고 함수 내부에 넣거나 또는 선언된 변수를 바로 넣어 비교하는 명령어(사용법은 유사하긴 하다)들을 사용하는 법을 풀어서 설명하고 있다.


2.쉬워 보인다고 빠르게 넘기면서 코드를 작성하는 실수를 반복하지 말자. 유사한 내용이 두세번 반복될 때는 무언가 숨은 의도(숨기지도 않았지만)가 있는지를 확인해야 한다.
예를 들어 .equal이 아닌 .toString이 붙어있다면 결과값과 비교돼야 할 값은 number타입이 아닌 string타입('2')을 넣어줘야 한다.


3.당연한 내용이지만 한번 정리하자면 string타입의 값은 더할 경우 다른 타입의 값들도 string으로 변환되어 과정이 처리되지만 +기호가 아닌 다른 연산기호를 사용할 경우 그 내부 값들이 숫자로 변형되어 처리된다. 주의할 점은 이때 숫자가 아닌 값이 number타입으로 변형될 경우 계산 결과는 NaN이 나오게 된다. 
1 + '1' = '11'
1 - '1' = 0
11 * '1' = 11
1 + '하나' = '1하나'
1 - '하나' = NaN
3 - true = 2      // true = 1
3 + false = 3     // false = 0
3 * false = 0


4. 장황하게 설명했지만 아래 설명과 같이 outer가 먼저 실행된다면 내부 지역변수 age가 24로 설정된 상황에서 26으로 재할당을 해주기 때문에 변수는 27이 나와야 맞다.
자세히 보니 outer 내부에서 물어본 값이기 때문에 inner 함수는 outer지역변수로 선언이 되어있는 것이라 바로 사용하는게 맞다. 원하는 값은 지역변수 24->26인 26이다.
아래 /// @@@ ///내용의 경우 본인이 이해할 때 어디가 헷갈렸는지 기록하기 위해 남겨둔다.

///아래의 경우 지역변수에 대한 이해가 필요하다.
당연하게 innerFn()이 위에서 보이기 떄문에 위에 있는 innerFn만 작동시켜야 하는데
이상하게 그 상위에 있는 outerFn도 작동된 결과값이 나와버린다. 왜 그럴까?
처음 봤을 때는 호이스팅과 스코프의 복합작용이라고 생각해서 호이스트를 검색해봤다.
하지만 hoisting은 함수 선언문(function x =(){})에만 적용될 뿐 함수표현식(let a = function(){})에는 적용되지 않았으며 함수표현식의 선언이 호출보다 아래에 있는 경우 ReferenceError가 발생한다. 하지만 같은 지역의 경우에만 호이스팅이 되지 않는 경우 문제가 생기는 것이고 아래와 같이 하위지역에서 호출한 변수(또는 함수)는 지역변수에서 찾을 수 없을 경우 상위지역으로 한단계씩 탐색 범위를 넓히기 때문에 global(예시)변수인 innerFn을 찾을 수 있었고 그것을 적용해  함수 내부에서 실행된 global함수호출이 정상적으로 작동할 수 있었다. 아래의 함수의 주석을 보면 더 쉽게 이해할 수 있다.///

 let age = 27;           //global변수 age
    let name = 'jin';    //global변수 name
    let height = 179;    //global변수 height

    function outerFn() { //global변수? outerFn 함수선언식
      let age = 24;      //지역변수 age 선언
      name = 'jimin';    //name탐색 후 지역변수 선언이 없어 global변수 name값 재할당
      let height = 178;  //지역변수 height 선언

      function innerFn() {  //closure 함수 선언
        age = 26;           //지역변수 age가 없어 상위 outer 지역변수 age에 재할당
        let name = 'suga';  //지역변수 name 선언
        return height;     //함수 실행시 height값 반환(상위 outer 지역변수 height)
      }

      innerFn();     // innerFn함수 실행(탐색시작) -> outer지역변수 innerFn실행
      
 @@(이건 틀린 설명 innerFn()이 outer밖에 있다고 해도 이상하다 )@@innerFn 지역변수 탐색(없음) -> 상위 outer 지역변수 탐색(없음) -> global변수 탐색(innerFn = outerFn()) -> 함수 outerFn실행@@@@@@@@@@@

      expect(age).to.equal(26);        //24(지역선언) -> 26(innerFn 재할당)
      expect(name).to.equal('jimin');  //'jin'(global선언) -> 'jimin'(outer 재할당) -> innerFn 내부 지역변수 name 재선언(outer에서 사용 불가)->'jimin'

      return innerFn; 
    }
 
 const innerFn = outerFn(); //global 변수 innerFn에 outer함수 할당(위에서는 사용하지 않는다)


5. obj.length 값은 undefined다. array가 아닌 obj에는 .length를 사용할 수 없다. 또한 배열에는 사실 키값(0,1,2,3등 순서)이 부여된 obj라는 느낌이기 때문에 obj[1]같은 키워드를 사용한다고 해도 키값을 순서에 맞는 숫자로 직접 지정해 준 obj가 아닌 경우 순서(0~n)를 []에 입력해도 그 순서의 값은 받아올 수 없다.


6.객체 내부의 value를 받아오기 위해서는 key를 사용해야 하는데 사용법인 닷노테이션과 브라켓노테이션을 주의해서 사용하자. obj.key의 사용은 당연하기 때문에 헷갈릴 일이 없지만 obj['key']는 헷갈릴 여지가 충분하다. 닷노테이션은 함수등 내부에서 사용할 경우 이상하게 사용되는 경우가 많기 때문에 백틱 또는 함수내부에 호출 등의 사용시에는 브라켓노테이션(obj['key'])를 이용하는 습관을 가져야한다.


7.얕은 복사와 깊은 복사가 있는데 객체나 배열을 복사하는 경우 대부분은 얕은 복사(주소값만 받아오기)로 
원본파일 또는 복사파일 중 어떤 것을 수정해도 모두가 변경되지만(사실은 모두가 단 하나의 저장소의 위치를 가르키고 있을 뿐이다) 깊은 복사를 하는 경우에는 새로운 객체를 새로운 heap에 할당하여 만들기 때문에 서로 다른 객체 또는 배열이 된다. 문제는 깊은 복사를 한다고 해도 객체의 내부에 있는 객체 또는 배열의 키값은 주소로 복사를 하기 때문에 객체의 내부에 있는 데이터를 지울 경우 객체의 객체 내부 정보는 날아가버릴 수 있다.
(이전에 작성한 내용이지만 같은 부분을 또 틀려버렸다..)


8.아래와 같은 배열이 있는 경우 1,2번째 변수만 지정한 수 array와 대입시키면 1,2번째 변수만 빼올 수 있다.
const array = ['code', 'states', 'im', 'course']

    const [first, second] = array
    expect(first).to.eql('code')
    expect(second).to.eql('states')


9.@@@ 언젠간 사용할 것 같아 다시 한번 기억해야 할 것 같다.
//@나머지부분은 다 객체로 떄려박힌다는 사실을 잊지말자///
  it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #1', () => {
    const student = { name: '최초보', major: '물리학과' }
    const { name, ...args } = student

    expect(name).to.eql('최초보')
    expect(args).to.eql({major: '물리학과'})
  })
  
  
@@@@@@@//키값들만 저장된 객체도 아닌데 getSummary가 course를 불러서 사용한다는 점이 상당히 신기하다. 만약 값이 반대였다면 이해할 수 있겠는데 어떻게 키(양자역학):값(미지정)으로 설정되어 있는데 값을 호출해서 키를 받을 수 있을까?..@@@@@@@@@@@@@@@

  it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #2', () => {
    const student = { name: '최초보', major: '물리학과', lesson: '양자역학', grade: 'B+' }

    function getSummary({ name, lesson: course, grade }) {
      return `${name}님은 ${grade}의 성적으로 ${course}을 수강했습니다`
    }

    expect(getSummary(student)).to.eql('최초보님은 B+의 성적으로 양자역학을 수강했습니다')
  })


/// 이런 여러가지 중간 중복값들이 설정될 경우 후분위에 적힌 내용이 최종적으로 시행되기 때문에 재할당이 되어버려 name은 '박해커', age는 20이 된다
    const changedUser = {
      ...user,
      name: '박해커',
      age: 20
    }

 

10. DOM에서 알아야 할 부분은 앞에 작성한 DOM부분을 참고했다. 

document.createElement('div')로 div태그쌍을 만들 수 있으며 
 const tweetDiv = document.createElement('div')로 tweeDiv라는 div요소를 만들 수 있다
 하지만 이는 연결이 되어있지 않기 때문에 별개의 상태이다.
 연결은 APPEND로 할 수 있다.

DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인할 수 있습니다. 셀렉터로는 HTML 요소("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용됩니다.
  const oneTweet = document.querySelector('.tweet') //클래스 이름 tweet 조회
  const tweets = document.querySelectorAll('.tweet')//tweet 인 모든 HTML요소를 유사 배열로 조회
  const getOneTweet = document.getElementById('container')//에전방식으로 조회

oneDiv.textContent = 'dev'; //추가가 아닌 변경이라고 할 수 있다.
 oneDiv.classList.add('tweet')//add사용으로 class tweet를 추가했다.

container.append(tweetDiv)//예시용 생성 후 
 tweetDiv.remove() // 이렇게 append 했던 요소를 삭제할 수 있다.
 document.querySelector('#container').innerHTML = ''; //이렇게 콘테이너의 자식을 모두 지울 수 있다.

document.body.append(tweetDiv)로 div요소를 body요소에 추가할 수 있다 
 생성한 tweetDiv 를 container 에 넣기 위해서는, container 를 먼저 찾아야 합니다
 const container = document.querySelector('#container')//콘테이너 위치 찾기
 const tweetDiv = document.createElement('div')       //div태그 만들기
 container.append(tweetDiv) //div 콘테이너에 부착
 const span = document.querySelector(‘span’);  //span찾기
 const divB = document.querySelector(‘.b’);    //.b클래스 찾기
 divB.appendChild(span);                       //.b클래스의 자식으로 부착 (위와 같은 느낌)

 

복습도 쉽지는 않다.

koans를 복습하고 DOM을 복습했는데 DOM은 틀린 부분이 딱히 있거나 문제를 풀지 않았기 때문에 정리한 요소를 다시 읽어보며 복습을 했다. 또한 유효성검사, 아고라스테이츠만들기에도 DOM을 이용한 경우가 많기 때문에 이 부분에서는 딱히 더 회고할 일을 찾기가 쉽지 않았다.