[항해99][3주차] #0. React 입문주차 SA

Hajun Song·2022년 7월 1일
0

항해99

목록 보기
8/8
post-thumbnail

React 입문주차 SA


JavaScript의 자료형과 JavaScript만의 특성

0. 느슨한 타입(loosely typed)의 동적(dynamic) 언어

타입
자료형을 의미하는 타입은 int, short, float, bool 등이 있다.
bool을 이용해 참거짓을 나타내는 자료를 만들고,
float을 이용해 실수를 나타내는 자료를 만들 수 있다.

하지만 이것은 정적 언어(C,C++,C#,JAVA 등)에 해당되는 사항이다.
깐깐하게 체크하며 맞지않는 자료가 들어가면 화를 낸다.

JavaScript
JavaScript느슨한 타입동적 언어이다.
한마디로 변수에 융통성이 있다. 변수의 자료형을 미리 선언하지 않아도 된다.
기본적으로 JavaScript의 변수는 특정 타입과 연결되지 않으며,
모든 타입의 값으로 할당 또는 재할당이 가능하다.

let num = 5     // num의 자료형은 숫자
foo = 'five'    // num의 자료형이 문자로 자연스럽게 재할당 됨
foo = true      // num의 자료형이 불리언으로 재할당 됨

1. JavaScript 형변환

암시적 변환
앞서 다룬 내용으로 JS에서는 별다른 노력없이 쉽게 자료형 재할당이 가능하다.
변수에 데이터를 입력하면 자바스크립트 엔진에 의해 자동으로 데이터 타입이 변경된다.

명시적 변환
하지만 동일한 내용의 자료형을 바꾸는 일에 그 내용을 하나하나 적을 필요는 없다.
유저가 명시해서 형변환을 할 수 있는 형변환 메서드가 충분히 제공되기 때문이다.

0. 숫자 -> 문자열 : String()

String() 함수를 이용해 숫자를 문자로 변환할 수 있다. 그 외의 다른 메서드는 아래와 같다.

💡 진수 설정이 가능한 toString()
toString() 은 2~36의 숫자를 사용한다.

let num = 72;
num.toString(); //”72"
num.toString(2); //”1001000"
num.toString(8); //”110"
num.toString(36); //”20"

💡 반올림하여 유효숫자 설정이 가능한 toFixed()
toFixed() 은 0~100의 숫자를 사용한다.

let num = 42.19587653;
num.toFixed(); //”42"
num.toFixed(2); //”42.20"
num.toFixed(8); //”42.19587653"
num.toFixed(-1); //에러

1. 문자열 -> 숫자 : Number()

Number() 함수를 이용해 문자를 숫자로 변환할 수 있다. 그 외의 다른 메서드는 아래와 같다.

💡 정수로 변환 parseInt(), 실수로 변환 parseFloat()

2. 자료 -> Boolean : Boolean()

Boolean() 함수를 이용해 다른 자료형을 Boolean 타입으로 변환시 그 결과는 아래와 같다.

//true						//false
Boolean(127);				Boolean(0);
Boolean('1');				Boolean(NaN);
Boolean(true);				Boolean(null);
Boolean(Object);			Boolean(undefined);
Boolean([]);				Boolean( );

연산자 변환
숫자형 데이터는 문자형 데이터와 더할 때 문자형 데이터가 된다.
이를 이용하여 숫자형 데이터를 손쉽게 문자형 데이터로 변환할 수 있다.

let num = 72;
num = 72+''		// 결과 : "72"
//숫자 + 문자열(공백)이므로 문자열

2. ==, ===

==
동등연산자 ==는 비교하는 두개의 데이터가 같은지 비교해주는 비교 연산자이다. 이때 자료형은 고려하지 않는다.

let a='123'
let b=123
console.log(a==b) 		// 결과 : true
console.log(true==1)	// 결과 :true

===
일치연산자 ===는 비교하는 두개의 데이터 뿐만 아니라 자료형까지 맞아야 true를 반환해준다.

let a='486'
let b=486
console.log(a===b)		// 결과 : false
console.log(true===1)	// 결과 : false

3. 동적(dynamic) 언어의 문제점

느슨한 타입(loosely typed)의 동적(dynamic) 언어의 문제점은 무엇이고 보완할 수 있는 방법에는 무엇이 있을지 생각해보자.

문제점 : 무지성 변수생성
말 그대로 변수를 생성 할 때 생각이 없다.
'이건 어떤 자료형으로 써야지'와 같은 설계가 제대로 되어있지 않으면 문제가 커진다.
이후에 변수에 예상치 못한 자료형이 들어와 에러가 났을 때 해결이 쉽지 않다.

보완방법 : 항상 깨어있으라
보라. 에러가 도둑같이 임하리니...

4. undefined와 null의 미세한 차이

undefined
undefined의 사전적 의미는 ‘정의되지 않은’이란 뜻이다.
변수를 선언한 이후 값을 할당하지 않은 변수를 참조하면 undefined가 반환된다.
undefined의 자료형은 undefined이다.

null
null은 어떤 값이 의도적으로 비어있음을 표현한다.
값이 없는 변수를 참조하면 null이 반환된다.


JavaScript 객체와 불변성이란 ?

0. 기본형 데이터와 참조형 데이터

데이터 타입
변수는 변수명과 데이터 값을 지닌 주소를 가지고 있다.
데이터 타입(자료형)은 기본형 타입참조형 타입으로 나뉜다.
이는 컴퓨터가 보다 효율적으로 데이터를 관리하기 위해 설정되었다.

0. 기본형 타입

기본형 데이터 타입으로는 숫자,문자열,불리언,null,undefined 등이 있다.
임의의 기본형 타입은 각자 변수명과 데이터 주소를 갖는다.
데이터 주소에 데이터가 담기고 해당 주소에서 읽어오는 방식이다.

기본형 타입은 할당이나 연산시에 데이터가 복제된다.
즉 또 다른 데이터 주소에 데이터를 남기는 것이다.
이로서 자유로운 수정이 가능하다.

//변수명 데이터(예시 데이터주소:2000)
let a = 362
console.log(a)	// 결과 : 362
let b = a
//변수명 데이터(a의 값을 가져와 다른 데이터주소2001에 담고 사용한다.)
console.log(b)	// 결과 : 362
a=472
console.log(a)	// 결과 : 472
console.log(b)	// 결과 : 362
//a를 바꿔도 b는 a와 다른 복제된 데이터에서 값을 가져오므로 변하지 않음.

1. 참조형 타입

참조형 데이터 타입으로는 객체,배열,함수,날짜,Set 등이 있다.
임의의 참조형 타입도 변수명과 데이터 주소를 갖는다.
데이터 주소에 데이터가 담기고 해당 주소에서 읽어오는 방식이다.

하지만 참조형 타입은 할당이나 연산시에 데이터를 참조만 한다.
즉 같은 데이터주소에서 값을 읽는 것이다.
무거운 배열과 같은 데이터를 가볍게 다룰 수 있지만 수정이 제한된다.

//변수명 데이터(예시 데이터주소:2000)
let a = [1,2,3]
console.log(a)	// 결과 : [1,2,3]
let b = a
//변수명 데이터(a의 데이터주소를 가져와 복사하지 않고 참조한다.)
console.log(b)	// 결과 : [1,2,3]
a[2]=472
console.log(a)	// 결과 : [1,2,472]
console.log(b)	// 결과 : [1,2,472]
//a를 바꾸면 같은 데이터주소를 참조하는 b의 값도 바뀐다.

1. 불변 객체를 만드는 방법

const
이처럼 참조형 타입의 데이터는 변수가 서로 주소를 참조하는 과정 속에서 그 값들이 엮이고 섥혀 수정하기 어려워진다. 그렇다. 변수가 바뀌는게 싫으면 상수를 쓰면 된다.
상수 선언 const를 이용해 생성된 값은 재할당이 불가하다.

const a = 'Jhon'
a='Song'
console.log(a) // 에러 : Assignment to constant variable.

하지만 그것은 객체 재할당에만 해당된다. 객체의 속성의 변경은 어떨까.

const a = [1,2,3]
a[1]=0			
console.log(a)	// 결과 : [1,0,3]
a=[4,5,6]
console.log(a)	// 에러 : Assignment to constant variable.

상수와 주소가 묶인 것은 객체일 뿐 객체와 묶인 객체의 속성 자체에는 접근이 가능하며 정상적으로 수정이 된다.
이때 아얘 수정을 막아버리고 싶다! 할 때 사용할 수 있는 함수가 있다.

Object.freeze()
상수 선언은 객체 재할당을 막아주지만 객체의 속성 변경은 막지 못한다. Object.freeze()객체의 속성 변경을 막는 함수이다. 하지만 재할당은 가능하다.

let a = [1,2,3]
Object.freeze(a)
a[1]=0			//객체의 속성(요소)에 접근
console.log(a)	// 결과 : [1,2,3] 불발.
a = [4,5,6]		//객체의 재할당
console.log(a)	// 결과 : [4,5,6]

썰어서 꽝꽝 얼려둔 냉동삼겹을 먹어본적이 있는가. 그들은 녹기 전까지 절대로 분리되지 않는다. 하지만 삼겹을 꺼내고 오리고기를 넣어두는 것을 가지고 누가 뭐라고 하겠나.

const a = Object.freeze([1,2,3])
끔찍한 혼종. const재할당 불가freeze객체 속성 변경 불가를 합쳐보자.
그는 무적이다.

2. 얕은 복사와 깊은 복사

얕은 복사
얕은 복사는 앞서 말한대로 참조형 타입을 재할당 할 때 주소값만을 가져와 참조하는 것을 말한다. 복사가 아니라 빔프로젝터의 느낌이다. a가 바뀌면 a를 바라보는 b도 바뀐다.
그래서 바뀌지 않는 불변객체도 만들며 위에서 주절주절 떠들었지만 사실 그럴 필요는 잘 없다.

깊은 복사
우리에겐 이러한 얕은 복사의 문제를 해결할 수 있는 깊은 복사가 있다.
깊은 복사된 객체는 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전 끊어져있다.
깊은 복사는 주소만 가져오는 것이 아니라 그 값을 가져오는 복사이다.

0. 필사

let a = [1,2,3]
let b = [1,2,3]

그렇다. 똑같이 따라쓰면 된다. a를 수정해도 아무런 문제가 일어나지 않는다.

0.5. 전개 연산자

let a = [1,2,3]
let b = [...a]

전개연산자는 ...를 붙여 내부의 값들을 가져오는 역할을 한다.
1겹의 배열에 있어서는 훌륭한 깊은 복사의 역할을 수행 할 수 있다.
하지만 배열안에 배열이 있다면 얕은 복사가 된다.
전개 연산자? [개념정리] javascript 모아보기

1. JSON.stringify() / JSON.parse()

0. `JSON.stringify()`를 사용하면 객체를 json 문자열로 변환한다.
1. 변환되는 과정 속에서 원본 객체와 연결이 전부 끊어진다.
2. `JSON.parse()`를 사용하면 json 문자열을 다시 원래 객체로 만들어준다.
3. 따란✨
let a=[1,2,[3,4]]
const b = JSON.parse(JSON.stringify(a)); 
b[2]=367
console.log(a)	// 결과 : [ 1, 2, [ 3, 4 ] ] 	아무런 변화 없다.
console.log(b)	// 결과 : [ 1, 2, 367 ]		잘 적용 된다.

이 방법이 가장 간단하고 다중배열도 가능하고 쉽지만 다른 방법에 비해 연산이 느리다.

2. 재귀함수

재귀함수를 이용해 요소들을 하나씩 꺼내서 저장한다.


호이스팅과 TDZ

0. 컨텍스트와 스코프

컨텍스트
실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다. 컨텍스트를 구성할 수 있는 방법으론 전역공간과 함수 등이 있다. 스코프체인을 통해 컨텍스트 외부로의 접근이 허용되나, 그 반대는 허용되지 않는다.

스코프
스코프변수에 접근할 수 있는 범위,즉 변수의 유효범위를 말한다. 이러한 스코프를 이용해 변수를 안에서부터 바깥으로 차례대로 검색하는 것을 스코프체인이라고 한다.
코드 상에서 어떤 변수에 접근하려고 하면 스코프체인에 따라 함수 내부(실행 컨텍스트)에서부터 함수 바깥(전역 컨텍스트)까지 순차적으로 탐색을 실시한다.

//ex0) a를 찾을때 내부부터 찾는다.
let a = 3	//전역 스코프
function numa(){
  let a =1  //내부 스코프
  return a
}
console.log(numa())	// 결과 : 1
//ex1) a를 찾을때 내부에 없으면 전역 컨텍스트에 있는지 찾는다.
let a = 3
function numa(){
  return a
}
console.log(numa())	// 결과 : 3
//ex2) 내부에서 선언한 변수는 오직 내부에서만 접근할 수 있다.
function numa(){
  a=1
  return a
}
console.log(a)		// 결과 : 에러 a is nor defined

1. 호이스팅, TDZ

TDZ(Temporal Dead Zone)
TDZ는 선언 전에 변수를 사용하는 것을 비허용하는 가상 공간의 개념이다.
변수를 선언한 이후에 변수를 호출하는 것은 문제가 없지만 변수를 선언하기도 전에 호출하는 것은 불가능하다. 변수, 함수 모든 것들을 컨텍스트 내부 전체를 처음부터 끝까지 훑어나가며 순서대로 수집하기 때문이다.

console.log(a)	// 결과 : 에러 a가 머여?
let a=3

호이스팅 var, function, import
하지만 TDZ를 해소하기 위해 함수 혹은 특정 변수들을 최상단으로 끌어올리는 가상의 기능이 있다. 가장 큰 예시로 함수가 대표적이다. 우리는 함수를 위에 적든 아래에 적든 순서가 뒤바뀌어 있든 정상적으로 작동하는 모습을 본 적이 있을 것이다.
아래의 코드는 홈페이지가 틀어지면 게시판 불러오기 함수를 실행하는 예시이다. 함수 호출보다 게시판 불러오기 함수 정의를 더 아래에서 수행했으나 문제없이 작동했다.

$(document).ready(function () {
    show_notice()
});
// 게시글 불러오기
function show_notice() {
    let team = window.location.href.split('team/')[1].split('/')[0]
    ...
}

var도 가능하다. 다만 변수의 선언부만 가져올 뿐, 그 값은 가져오지 않는다.

console.log(a)	// 결과 : undefined
var a=3
console.log(b)	// 결과 : 에러 b...?몰..루..
let b=3

이렇든 저렇든 가독성과 유지보수를 위해서라도 스코프체인이 꼬이는 것을 방지하기 위함에라도 선언문들은 상단에 적는 연습을 하는것이 좋다.

2. 함수 선언문과 함수 표현식에서 호이스팅 방식의 차이

함수 선언문과 함수 표현식
둘 다 함수를 새롭게 정의할 때 쓰이는 방식이다. 그 중 함수 선언문은 function 정의부만 존재하고 별도의 할당 명령이 없는 것을 말한다. 반대로 함수 표현식은 정의한 function을 별도의 변수에 할당하는 것을 말한다.
가장 큰 차이로는 함수 선언문에는 함수명이 필수적이고 표현식은 그렇지 않다는 것이다. 물론 함수 표현식의 변수명이 함수의 name 프로퍼티에 할당된다.

호이스팅 방식의 차이
함수 선언문과 함수 표현식의 결정적인 차이는 변수를 선언했다는 것이다.

console.log(sum(1,2))
console.log(multiply(3,4))
function sum(a,b) {				//함수 선언문 sum
  return a+b}
var multiply = function (a,b) {	//함수 표현식 multily
  return a*b}

이 코드에 대하여 호이스팅이 적용된 흐름의 모습을 시각화 하면 아래와 같다.

function sum(a,b) {			//함수는 전체를 호이스팅 한다.	
  return a+b}
var multiply;				//변수는 선언문만 끌어올린다.
console.log(sum(1,2))		// 결과 : 3
console.log(multiply(3,4))	// 결과 : 에러 multiply는 함수가 아닙니다!
multiply = function (a,b) {
  return a*b}

3. 콜 스택

콜 스택
콜 스택은 JS 코드 실행 시 전역 컨텍스트부터 사용할 컨텍스트까지 쌓아올리는 형식의 데이터 구조이다. 콜 스택에 쌓아올라간 컨텍스트는 코드의 흐름에 따라 함수의 실행들이 종료될 때 해소되며, 전부 해소되면 js는 종료된다.

이때 컴퓨터는 함수 A를 진행하다가 함수 B를 만나면 A를 다하고 B를하지 않고, A는 내버려 두고 B를 하러간다. B가 마무리 되면 중단되었던 A를 마저 한다. 흘러가다가도 다카포가 나오면 돌아가는 악보를 보듯 컴퓨터는 정말 까라는대로 깐다. 당연한 이치이다.

//js 실행
var a = 1			//콜 스택 0층 전역 컨텍스트 a=1, b =2
var b = 2
aum()				//함수 aum() 호이스팅으로 정상 실행
function aum() {	//콜 스택 1층 aum() 컨텍스트 a=12 b=2(2번 줄 스코프 체인)
  var a=12//
  function bum(){	//콜 스택 2층 bum() 컨텍스트 a=7,b=0
    var a=7
    console.log(a,b)
    // 결과 : 콜 스택 2층 [a=7, b=undefined (TDZ,선언문만 호이스팅)]
    var b = 0
  }					//bum() 종료 콜 스택 2층 제거 / 1층 a=12 b=2
  bum()
  console.log(a,b)
  // 결과 : 콜 스택 1층 [a=12 b=2]
}					//aum() 종료 콜 스택 1층 제거
console.log(a,b)
// 결과 : 콜 스택 0층 전역 컨텍스트 [a=1, b=2]
//콜 스택 다 비움 => js 종료.

4. 변수 은닉화

변수 은닉화
변수 은닉화는 하위 컨텍스트를 탐색하지 않는 스코프체인의 특성을 이용해 외부에서의 변수 접근 권한을 제어하는 개념이다. 외부에서 변수를 직접적으로 수정할 수 없으므로 더 유연하고 모듈화하기 쉽다.

var outer =function() {
  var a=1;
  var inner = function () {
    return ++a;
  };
  return inner
}
var outer2 = outer();
console.log(outer2());	//2
console.log(outer2());	//3
console.log(outer2());	//4 |outer2()를 이용해 함수 내부의 컨텍스트 만을 이용하므로
let a=3					//	|함수 내 a에 대한 외부에서의 접근이 제한된다. 
console.log(outer2());	//5 |물론 함수 밖 a와 별개로 돌아가므로
console.log(a)			//3	|전역 컨텍스트에 있는 a는 변화가 없다.

🐤 실습 과제

콘솔에 찍힐 b 값을 예상해보고, 어디에서 선언된 “b”가 몇번째 라인에서 호출한 console.log에 찍혔는지, 왜 그런지 설명해보세요.
주석을 풀어보고 오류가 난다면 왜 오류가 나는 지 설명하고 오류를 수정해보세요.

let b = 1;
function hi () {
    const a = 1;
    let b = 100;
	b++;
console.log(a,b);	// 10번줄 주석 참고
}
//console.log(a);	// 스코프체인은 하위 컨텍스트를 탐색하지 않는다. X
console.log(b);		// 스코프체인은 하위 컨텍스트를 탐색하지 않는다. 1 (1번줄)
hi();				// 6번줄에 의해 내부 컨텍스트에서 찾는다. 1 101 (3번, 4번줄)
console.log(b);		// 1 (1번줄)
profile
일단 똥을 싸라, 그리고 박수칠 때 까지 닦아라.

0개의 댓글