TIL
코딩 부트캠프 4주차를 맞이한 내게 소소한 변화가 한 가지 더 생겼다. 지난 3주간은 머릿속으로 과제, 학습 내용, 복습할 내용을 대략 정리할 수 있어서 하루 일정을 짤 수 있었다면, 이제는 과제에 집중할 시간이 더 많이 필요하게 되었고 내가 스스로 찾아보고 싶은 내용들이 많아져서 구체적인 스케줄링이 필요해졌다.
그렇게 월요일 아침에 스케줄러를 꺼내놓고 일주일을 그리며 펜을 들었다.
다음 날 아침이 되면 전 날 계획했던 내용을 달성하였는지 체크하며 확인하고, 학습하다가 더 공부할 내용이 생기면 차곡차곡 쌓아두고 틈틈이 학습하게 됐다. (당연히 달성하지 못한 것도 있다-노란색과 까만색)
날이 갈수록 착실한 학생이 되는 듯 보이지만 사실 이번 주는 실제 git을 이용해 fork, clone, add, commit, push, pull의 과정을 모두 밟아볼 수 있는 과제를 2개나 진행해야 했기에 온 신경이 git workflow 이해하기에 쏠려서 다른 것들을 놓칠까 봐 밸런스를 놓치지 말아야겠다는 생각에 스케줄링을 시작한 것도 있다.
게다가 TDD(test driven development)에 대해 학습하면서 단순 알고리즘 풀이 문제를 넘어서 내가 짠 코드가 제대로 작동하고 있는지를 확인하기 위해 다양한 테스트 케이스를 mocha, chai 등의 툴을 이용해서 구현하는 과정이 녹록지 않았다. 다행히 주 후반에 과제를 마치고 리뷰를 하다 보니 chai 툴 활용에는 자신감이 붙었다. 나는 매 과제를 마주할 때마다 [멘붕 → 초집중 → 체화]의 사이클을 통해 계속 성장하고 있다.
변수의 전달
Test Builder 과제 진행하면서 L&L
Scope
코딩 팁
primitive type vs reference type : type에 따라 변수의 전달 방식이 다름
primitive type인 경우 : parameter에 값을 보내고 원본이 같이 바뀜 (이건 마치 → 다른 이름으로 저장)
- ex) let a = 13; // a는 13이다.
- let b = a; // b는 a가 가지고 있던 13을 가지고 와서 저장하지만 a와 연결되어 있지는 않음(마치 “다른 이름으로 저장”)
- b = 37; // b에 37을 다시 할당
- console.log(a); 13 // b가 a의 원형을 가져가서 37로 탈바꿈해도 a는 바뀌지 않고 그대로
reference type : 주소 값을 parameter로 보내고 원본이 바뀌지 않음 (이건 마치 → 바로가기 복사)
- ex) let a = { c: 13 }; // a는 3을 key로, 13을 value로 가지는 객체
- let b = a; // a가 가지고 있던 { c : 13 } 객체를 복사해서 b에 저장, 이때부터는 b와 a는 같은 몸(마치 “바로가기 복사”)
- b.c = 37; // b가 가지고 있는 객체 { c : 13 }에서 c라는 key를 이용해 해당 value인 13을 37로 재할당
- console.log(a); { c : 37 } // b에서 13이 37로 바뀌어서 a의 value도 바뀜
문제와 해답(1)
①의 console.log(param)은 param은 변수로 아직 선언되지 않음
②의 console.log(param)은 ‘good bye’;
③의 console.log(param)은 함수 정의가 끝난 상태에서 변수만 출력하면 error
④의 console.log(param)은 ‘hello world’
문제와 해답(2)
param에 obj를 넣어서 key greeting에 해당하는 value ‘hello world’를 ‘good bye’로 바꿔줌.
obj는 객체여서 바로 해당 value 값이 변경되고,
따라서 함수에 obj를 넣어주면 obj는 { greeting : ‘good bye’ }로 바뀜.
변수의 전달 정리
↑다른 이름으로 저장 ↑바로가기 복사
Chai를 이용해서 describe → it 형식을 빌려서 for loop로 test case를 만들 때 순서:
① for문이 도는 동안에는 각각의 it 블록을 형성
② 그런 다음 it 안에 있는 function은 나중에 실행하면서 해당하는 테스트 값을 넣어줌
Mocha와 Chai의 차이점:
- Mocha는 실행 함수를 넣었을 때, 에러인지 아닌지 true와 false로 구분하는 테스트
- Chai는 실제 text case를 대입했을 때, 에러인지 아닌지를 보여줌
Scope의 필요성: scope가 정해져야 변수의 활용이 정확해짐
변수는 접근할 수 있는 범위가 존재하고, local scope 안쪽에서 선언된 변수는 밖(global scope)에서 사용할 수 없음
Scope 정의 : 변수 접근 규칙에 따른 유효 범위
- 변수는 어떠한 환경 내에서만 사용 가능하며, 프로그래밍 언어는 각각의 변수 접근 규칙을 가지고 있다.
- 변수와 그 값이, 어디서부터 어디까지 유효한지를 판단하는 범위
- JS의 경우에는 함수가 선언되는(lexical) 동시에 자신만의 scope를 가진다 → JS의 scope는 함수가 하나의 범위를 지정해주는 격
1. Scope 규칙 1 : local scope vs global scope 차이
안쪽 scope에서 바깥 변수/함수를 접근하는 것은 가능
however, 바깥쪽 scope에서 안쪽 변수/함수를 접근하는 것은 불가능
scope는 중첩이 가능: 함수 안에 함수 넣기 가능
global scope는 최상단의 scope, global scope에서 선언된 전역 변수는 어디서든 접근이 가능
지역 변수는 함수 내에서 전역 변수보다 더 높은 우선순위를 가짐
ex1)
전역 변수 name과 지역 변수 name이 다름
지역 변수는 함수 안에서 전역 변수보다 우선순위가 높아서 함수를 실행할 때 나오는 변수는 지역 변수 값을 따름
ex2)
ex1와 달리 지역 변수 내 선언(let)이 없음
이렇게 되면 함수 내 지역 변수가 전역 변수에 새로운 값을 할당시켜줘서 함수 종료 후에도 전역 변수의 값이 변경되어서 출력됨
2. Scope 규칙 2 : function scope vs block scope 차이
Block의 개념
- 중괄호({)로 시작하고 끝나는(}) 단위, curly bracket 단위
- 보통의 경우 scope를 구분하는 단위가 됨
ex1)
예제에는 함수가 없어서 for문부터 마지막 console.log까지를 function scope로 보고 있음
i는 for문에서 var로 선언되면서 전역 변수 역할을 하고 있음, 따라서 for문이 종료된 후 i를 출력하면 해당 값이 나옴
let을 쓸 것인가? var를 쓸 것인가?
var의 경우 한정된 block 범위를 벗어나서도 사용이 될 수 있음,
유효 범위를 알기 쉽지 않기 때문에 이를 방지하기 위해 let을 사용하는 것이 좋음
let과 var의 작동원리 보기:
greetSomeone 함수 내에는 3개의 변수가 var(function scope) 형태로 존재(firstName, greeting, time)
greeting이라는 변수가 함수 안에 들어 있어도 잘 작동함
let(block scope) 형태일 때 greeting은 함수 기준의 block에 갇히게 됨
return이 안쪽 block 바깥에서 실행되면 greeting이라는 변수를 읽어올 수 없음 → 에러 발생
block 안에서 debugger를 걸면 greeting이라는 변수가 존재하고 사용이 가능하게 나옴
const keyword
- const는 constant의 줄임말
- 정의: 값이 변하지 않는 변수, 즉 상수를 가리키는 키워드
- let과 동일하게 block scope를 따름
- 값을 재정의할 수 없음, 재정의 하려고 하면 TypeError 발생
Block Scope와 Function Scope에 관련된 Keyword 정리
var는 ES5까지 기본값, old way
user들이 Block 사이에서 변수 선언 시, block을 넘어서서는 변수 활용이 어려울 것이라는 생각을 많이 하게 되어서 새롭게 let keyword가 생겨남
var의 재선언도 문제를 일으키는 상황이 발생하여 let이나 const는 재선언이 불가능해짐
3. Scope 규칙 3 : 전역 변수와 window 객체
window : 전역 범위를 대표하는 객체
global scope에서 선언된 함수와 var 키워드를 이용해 선언된 변수는 window 객체와 연결
global scope에서의 함수를 이용한 변수와 window의 관계: 함수 선언을 하면 window 객체에서 확인 가능
var 키워드를 이용한 변수와 window의 관계 : var로 선언한 변수는 window 객체에서 확인 가능
주의 : 전역 범위에 너무 많은 변수를 선언하지 않도록 해야 함
전역 영역은 최상위 scope이기 때문에 어떤 프로그램/라이브러리가 어떤 변수를 사용할지 모름
→ 한 프로그램 파일 안에서 여러 개 js script 파일을 돌릴 수 있는데 전역 변수가 많이 선언되어 있으면 중첩되어 해당하는 변수를 사용할 수 있기 때문에 이를 방지하는 것이 좋음
→ 대신 { } 안에서 let으로 변수 선언하는 방법을 추천
4. Scope 규칙 4 : 선언 없이 초기화된 전역 변수
절대로! 선언 키워드(var, let, const) 없이 변수 초기화를 하지 말 것
선언이 없는 상태에서 변수를 사용하면 window 객체에 담겨 있음
ex) age = 100;
age === window.age // true 반환
선언이 없는 초기화를 막기 위해서는 Strict Mode를 사용하면 좋음
- strict mode를 사용하면 의도하지 않게 선언이 되지 않는 변수 사용을 에러로 알려주고 막아줌
- strict mode는 chrome 검사 모드에서는 어렵고 script 파일을 선언해야만 실행 가능
기억할 것!
- Scope는 변수를 사용할 수 있는 ‘유효 범위’
- Local Scope와 Global Scope 사이 변수 사용 방법
- 선언 key(let, const, var)의 차이점
→ let은 block 단위에서 유효 범위가 정의되어 헷갈리지 않고 가독성 면에서 좋음, 재선언에서도 버그를 줄여주는 키워드
- Block scope와 Function scope 단위 차이
- window 객체에 포함되는 변수: global scope에서 선언된 함수, var 키워드를 이용한 변수
- 선언 없이 초기화하지 말 것! (strict mode 없이는 에러가 발견되지 않음)
변수로 입력되는...args와 arguments의 차이
- ...args 나 arguments나 변수로 들어오는 값을 arguments로 인식하는 것은 같음
- arguments가 변수로 들어온 모든 값을 지칭하는 반면
- ...args는 지정된 변수와 함께 사용될 때 지정되지 않은 변수들을 가리킴
- ex1) 모든 변수를 가리키기 위해 ...args를 쓸 때 arg와 arguments
- ex2) 지정된 함수와 함께 ...args를 쓸 때 arg와 arguments
block scope : if문이나 for문에서 사용 {}
function scope : function을 선언할 때 사용 {}
chai를 이용해서 TDD를 할 때 테스트 케이스 it을 for문으로 생성할 때, 테스트 케이스 run 순서 이해하기
- for문이 도는 동안에는 it 블록을 먼저 형성
- for문의 끝난 다음에 it 안에 있는 실제 function을 이용한 테스트가 하나씩 실행된다고 이해하면 좋음
재귀 함수를 짤 때, 쉬운 조건 1개 그리고 복잡한 조건 1개로 함수를 간단하게 구조화하고 함수 안에 함수를 배치하는 것이 필요!
for문의 원형 : for(let i = 0; i < arr/str.length; i++)
초기화 조건이 없이 증감 조건을 달리 설정할 수 있음
for( ; num >= 1; num = num / 2) //이런 식으로…
str method는 read only이기 때문에 재할당이나 변환을 하려면 slice(substring은 자제) 등으로 새로 할당해주는 것이 필요
- ex1) let str = ‘abc’;
str[0]; // ‘a’
str[0] = str[0].toUpperCase(); // ‘A’ → upper case로 read는 가능
str; // ‘abc’ → 그러나 새로 할당되지는 않아서 원 문자열 그대로 반환
- ex2) let str = ‘abc’;
let arr = str.split(‘’) // arr = [“a”, “b”, “c”];
arr[0]; // ‘a’
arr[0] = arr[0].toUpperCase(); // “A”
arr; // arr = [“A”, “b”, “c”]
arr.join(‘’); // “Abc”
정규표현식 : 어떤 패턴을 찾거나 바꾸는데 용이,
https://regexr.com/ 에서 테스트하면서 만들 수 있음
str.indexOf(param)와 str.lastIndexOf(param)
- str.indexOf(param)은 str의 앞에서부터 param을 찾아서 몇 번째인지 보여줌
- str.lastIndexOf(param)은 str의 param이 여러 개이면 가장 뒷 param이 몇 번째인지 보여줌
“abc”.indexOf(“a”); // 0
“aaabc”.indexOf(“a”) // 0
“abc”.lastIndexOf(“a”); // 0
“aaabc”.lastIndexOf(“a”) // 2
“aaabc”.lastIndexOf(“a”, 1) // 0부터 1 사이 범위는 “aa”이고 마지막 a가 1번째여서 1
“aaabc”.lastIndexOf(“a”, 0) // 0까지 범위는 “a”이고 마지막 a는 0번째여서 0