TIL 21.09.24 Javascript

서재환·2021년 9월 24일
0

TIL

목록 보기
21/37

✍️ Javascript 기초 문법

✏️ 입력과 출력

  학습목표

입력값에 대한 출력값이 있다는 사실에 익숙해지고 javascript 코드 내에선 입력과 출력이 어떤 방식으
로 이루어지는 코드를 통해 살펴보자.

  입력과 출력

컴퓨터는 사용자의 입력에 대해 출력을 낸다. 예로 주소창에 '유투브'를 입력하면 글자가 화면에 보여
지게된다. 대단히 당연하게 여겨지는 부분이라 입력과 출력에 대한 것을 개념적으로 인지하는 시간이 필
요로하다. 개념적으로 인지한다는 것은 위의 개념이 javascript에선 어떻게 적용되는지 살펴보는 것이
다.
// fs(file system)이라는 라이브러리를 갖고와
const fs = require("fs"); 

// 파일을 읽을수 있는 readFileSync method를 사용해 ./input.txt 파일을 읽어들인다.
const input = fs.readFileSync("./input.txt", "utf8"); 

console.log(input) //hello, world!
위 코드를 통해 javascript 에서 입출력이 이루어지는 부분을 살펴보자.
여기서 입력에 해당하는 부분은 현재 작업 디렉토리에서 만들어놓은 'input.txt'파일이다.
그리고 출력은 해당 파일의 내용을 사용자에게 보여주는 'console.log(input)' 부분이다.
중간 과정은 사용자에게 보여주기위해 처리된 방식이라고 생각하기로 하자.

코드의 내용을 이해하는 것도 좋지만 여기서 살펴보아야 할 부분은 'input.txt'라는 파일이 사용자의 
입력이 되고 'console.log(input)'이라는 해당 명령어로 출력이 이루어졌다는 것이다.

이렇듯 코드에서도 stdin과 stdout의 적용 예시를 살펴 볼 수 있었고 해당 구조를 통해 앞으로 마주하
는 부분에 대해서 적용해보기로 하자.

✏️ 기본 용어

  식별자

[식별자 특징]
변수나 함수에 이름을 붙일 때 사용하는 단어
대소문자 구별, 유니코드 문자셋 이용

[식별자 규칙]
키워드 사용불가, 숫자 시작 불가, 특수문자 (_,$)는 시작 가능, 공백문자 포함안됨

  변수

변경가능한 값을 저장하기 위한 기억공간(memory)

여기서 변경가능하다라는 의미는 변수를 선언하고 값을 다시 할당할 수 있다는 의미이다. 값을 저장하고 
있기 때문에 컴퓨터 메모리 공간을 차지한다.

같은 이름으로 또 다시 선언하는 것은 불가하며 let으로 변수를 선언 그리고 필요에따라 값을 할당한다.
변수 사용 예시_1
let 나는기억공간의별칭 = "나는 기억 공간에 들어가는 값"
좌항은 공간에 대한 이름을 우항은 공간에 들어가는 값이 들어가는 부분이다.

변수 사용 예시_2
let name = "sjh", age = "2n", msg = "hello" 와 같이 한줄에 ','를 써서 한번에 여러개의 변수
를 선언할 수 있다.

  상수

변경 불가능한 값을 저장하기 위한 기억공간(memory)

선언 하자마자 값을 할당해야한다. 선 선언 후 할당은 상수의 값을 재할당하는 행위이기 때문에 에러를 
발생시킨다.

중복선언 불가능하다.

  정리

변수와 상수를 나눈 이유는 바뀔 수 있는 값에 대해서 변수를 사용하고 바뀌지 않는 고정값에 대해선 상
수를 사용하기 위함이다. 대개 상수는 대문자로 선언을 하고 '원주율', '지구 반지름', '주민번호' 등 
바뀌지 않는 값을 변수에 할당할 때 상수를 사용한다.

  호이스팅

변수 생성시 var을 사용하여 생성할 때 변수의 선언부가 위로 올라가는 현상을 호이스팅이라고 한다. 예
시를 통해 직관적으로 이해해보기로 하자.
console.log(name_1);
var name_1 = "sjh";
console.log(name_1);

<<<<<<<<<<<<<<<<<<<<
  
var name_2;
console.log(name_2);
name_2 = "sjh";
console.log(name_2);

>>>>>>>>>>>>>>>>>>>>
/*
undfined
sjh
undfined
sjh
*/
위코드로 작성한 결과 값과 아래 코드로 작성한 결과 값이 서로 동일하다. 호이스팅이 발생한 부분은 최
상단에 작성한 코드이고 풀어서 작성하면 아래와 같이 동작하게 된다. 즉 var로 변수를 선언할 시 할당
부분을 제외한 선언부가 최상단으로 올라가져 기입되는 것이다.

✏️ 자료형 종류

  원시타입

   Boolean
논리 값 true or false 에 해당

조건문에서 사용되며 true는 참을 false는 거짓을 나타낸다.
   null
null은 값이 비어 있다는 의미로 표현되는 자료형
존재하지않는(nothing), 비어있는(empty) 알수없는(unknown) 값을 나타내는데 사용


console.log(typeof null) //object

null의 타입을 찍어주면 object로 표시되는데 구버전과의 호환성을 위해 그렇게 표현한 것이지 원래 
원시 타입은 null 이다.
   undefined
선언 후 값을 할당하지 않은 변수에 해당 자료형이 '값'으로 들어가게 된다.
   number
정수(integer), 실수(부동소수점)을 표현. 정수의 한계는 ±2^53 이다.

부동소수점 연산의 경우 오차가 발생할 수 있는데 toFixed() 메서드를 통해서 극복할 수 있다.

console.log((123.0 - 123.456).toFixed(3)) 와 같이 작성할 경우 소수점 세자리이하에서 반올림
을 처리하라는 의미이다. toFixed(3)를 적용하지 않을 경우 실제 결과값은 오차를 발생시키기 때문에
위와 같은 메서드를 사용한다.

console.log(1/0);        //infinity
console.log(1/"hello"); //Nan
   string
let string = 'hello';    //홑 따옴표로 써도 되고

let string_2 = "hello"; //쌍 따옴표로 써도 된다.

console.log(`$(string) world`); //hello world
위와 같이 (``)$()를 사용해 변수의 값을 문자열과 함께 표시해줄 수 있다.
   symbol
문자열과 함께 객체로 사용

   객체타입

두개 이상의 원시자료형을 포함하거나 복잡한 개체(entity)를 표현할 수 있는 자료형

object는 Object() 혹은 중괄호({})를 통해 생성

object의 객체는 key: value 형태로 표현하며, 접근은 object.key 형태로 표현

아래 예시를 통해 객체가 메모리에 어떻게 저장되는지 살펴보기로 하자.
객체타입 예시

let user = {
  name: "john",
  age: 27,
};

console.log(typeof user); //object
console.log(typeof user.name); //string
console.log(typeof user.age); //number

user.weight = 76; //객체의 property를 추가

del user.weight // 객체의 property를 삭제한다.
1. 'user'라는 메모리 공간이 생긴다. 해당 메모리 공간은 'name'과 'age'를 저장하고 있는 공간의
   주소 값을 가리키고 있다.
   
2. 따라서 name.user 또는 name.age를 통한 값에 접근 할 때 'user'의 메모리로 가서 'user'가 참
   조하고 있는 공가안의 'name' 공간 또는 'age' 공간에 접근하여 값을 불러오는 것이다.

let user_1 = {
  name: "john",
  age: 27,
};

let user_2 = user_1 의 의미

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  
변수 user_2은 변수 user_1가 담고 있는 메모리 주소를 값으로 갖고 있다. 

즉 user_2는 user_1이 갖고 있는 주소값을 복사했기 때문에 user_1과 user_2가 서로 다른 메모리
상에서 만들어졌지만 가리키는 메모리는 같은 번지를 가리키는 것이다. 왜냐하면 user_1이 갖는 값과
user_2가 갖는 값이 '0x12341234'로 동일하기 때문이다.

   ✏️ 객체복사

   얕은복사

가리키는 대상 전체를 복사하는 방법인 얕은복사에 대해서 알아보자.
let user = {
  name: "john",
  age: 27,
};

let admin = user
    얕은복사_1
새로운 객체 adim을 생성후 for 문을 이용하여 user의 key에 접근하여 속성 하나하나 만들어주는 경우
가 있다. admini이라는 user와는 다른 주소를 갖고 있는 객체 공간에서 key와 value를 할당하는 것이
기 때문에 값이 프로퍼티 접근을 통한 값의 변경이 발생하더라도 서로 다른 값을 갖는다.

    얕은복사_2
얕은 복사를 만들 수 있는 두번 째 방법으로 Object 내 assign() 메서드를 사용하여 두개의 객체를 
병합해서 새로운 객체를 만드는 내부 메서드를 활용하는 방법이 있다.
let user {
  name: "john",
  age: 23;
}

let admin = Object.assign({}, user);
    얕은복사_3
세번째 방법으로 user 내의 field 값을 열거해서 얕은 복사를 새로운 객체를 만들 수 있다.

let user {
  name: "john",
  age: 23;
}

let admin = {...user}; //{user.name, user.age}
    얕은복사의 문제점
 아래와 같은 객체를 생성했다고 하자. 위에서 실시한 방법 중 하나의 방법으로 얕은 복사를 통해 객체
user를 복사했을 때 sizes가 가지고 있는 주소의 메모리 값을 복사하게 된다. 따라서 처음 시작 부분
객체 admin에 user를 할당할 때와 같은 문제, 즉 얕은복사를 한 변수안에 있는 size와 user의 size
가 같은 메모리의 주소값을 가리키는 경우가 발생하게 되는 것이다.

같은 주소 값을 가리키는 것에서 발생하는 문제점은 user.size.height++ 로 값을 변경하면 admin부분
admin.size.height도 값이 변경된다는 부분이다.
let user = {
  name: "john",
  age: 23,
  size : {
    height: 180,
    weight: 72,
  },
};

let admin = {...user} // 얕은 복사의 문제점을 아래의 도식을 통해서 이해할 수 있다.

   깊은 복사

    깊은복사 1
첫번 째 깊은 복사의 경우 for문을 이용하여 객체 내부 안에 값이 아닌 새로운 객체를 만났을 때의
조건일 때 copyObj(obj[key]) 를 사용해 객체를 복사하는 방법이 있다.

   깊은복사 2
두번째 방법으로 JSON.stringify(user)를 통해 객체를 문자열로 변환한 후(원본 객체와의 참조 끊김)
이의 결과 값을 JSON.parse()를 통해 다시 객체화 시키는 방법이 있다.

0개의 댓글