[JS] 2. Basic (2)




1. 자료형

자료형

  • 목적에 따라 특별한 성질이나 정해진 범주를 갖고 있는 데이터의 종류
  • 자바스크립트에서는 6가지의 원시 타입 자료형과 1가지의 객체 타입 자료형으로 구성


원시 타입(primitive type)

  • Boolean : 논리적인 값으로 true, false
  • null : 존재하지 않거나 유효하지 않은 주소 표시
  • undefined : 선언 후 값을 할당하지 않은 변수
  • number : 정수, 실수 등의 숫자, 정수의 한계는 +-2(53제곱)
  • string : 빈 문자열이나 글자들을 표현하는 문자열
  • symbol : 문자열과 함께 객체 property로 사용, ES6에 추가


객체 타입(object type)

  • object : 두개 이상의 복잡한 개체 저장 기능


typeof

let str = "hello";
console.log(typeof str); // string

console.log(typeof undefined); // undefined
console.log(typeof 123); // number
console.log(typeof 456n); //bigint
console.log(typeof 123.123); //number
console.log(typeof true); //boolean
console.log(typeof "hello"); //string
console.log(typeof Symbol("id")); //symbol
console.log(typeof Math); //object
console.log(typeof null); //object
console.log(typeof console.log); //function
  • typeof는 인수의 자료형을 반환하는 연산자
  • 연산자인 typeof x와 함수인 typeof(x)로 문법 지원


boolean

let number_check = true;
let age_check = false;

let value_check = 10 > 3
console.log(value_check) //true
  • boolean은 논리적인 값을 표현하는 자료형
  • 참인 true와 거짓인 false, 두 가지 값만 존재
  • 주로 조건문 등에서 동작 판단의 기준으로 사용


null

console.log(typeof null) // object > 하위 버전 호환성으로 object 표기

const null_check = null
console.log(null_check === null) //true
  • 값이 비어 있다는 의미로 표현되는 자료형
  • 존재하지 않는(nothing), 비어 있는(empty), 알수 없는(unknown) 값을 나타내는데 사용


undefined

let name;

console.log(name) //undefined
  • 값이 할당되어 있지 않은 상태를 나타날 때 사용되는 자료형
  • 벼눗 선언 후 초기화 하지 않는다면, undefined 로 자동 할당


number

let num1 = 123.0
let num2 = 123.456
let num3 = 1 / 0

console.log(num1 - num2) // -0.45600000000007
// 컴퓨터는 소숫점 연산을 변수의 메모리 한계로 인해 오차가 발생한다.
// Math 사용하면 이 부분을 좀 더 clear 하게 할 수 있다
console.log((num1 - num2).toFixed(3)) // 소수점 3째자리 까지로 반올림해라
console.log(num3) //Infinity
console.log(num1 / "hello") //NaN

  • 정수, 부동소수점(floating point) 숫자를 표현하는 자료형
  • 관련된 연산은 사칙연산이 대표적
  • 일반적인 숫자 외에 Infinity, -Infinity, NaN(Not a Number) 값은 특수 숫자 값이 포함
  • number에서는 2(53제곱)-1 보다 큰 값을 사용할 수 없으며, 더 큰 정수를 다루고 싶다면 bigint 자료형 사용 필요


string

let str1 = "hello"
let str2 = 'hello'

let num = 3
let str3 = `hello ${num}`
console.log(str3)
  • 문자, 문자열을 표현하는 자료형
  • 자바스크립트에서 문자열은 3가지 종류의 따옴표로 표현 가능
  • 큰 따옴표 “”
  • 작은 따옴표 ‘’
  • 역 따옴표(백틱) ``


객체 타입

let user = {
    name: "nahyun",
    age: 25
}

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

console.log(user) //{ name: 'nahyun', age: 25 }
console.log(user.name) //nahyun
console.log(user.age) //25

// 객체 요소 추가
user.height = 160; //{ name: 'nahyun', age: 25, height: 160 }
console.log(user);

// 객체 요소 삭제
delete user.age; //{ name: 'nahyun', height: 160 }
console.log(user);

  • 다수의 원시 자료형을 포함하거나 복잡한 개체(entity)를 표현할 수 있는 자료형
  • Object() 혹은 중괄호{}를 통해 생성
  • 개체는 key:value 형태로 표현하며, 접근은 object.key형태로 표현



2. obejct 복사

// user 를 수정해도 admin이 수정되고, admin을 수정해도 user가 수정된다.
// 메모리의 주소값만 복사한 것이기 때문에 같은 값들을 가리키게 된다.
let user = {
  name: "nahyun",
  age: 25,
};

let admin = user
console.log(admin) //{ name: 'nahyun', age: 25 }

admin.name = "jo"
console.log(admin) //{ name: 'jo', age: 25 }
console.log(user) //{ name: 'jo', age: 25 }
  • object의 값을 복사할 때는 대상 전체가 아닌 object 내 주소 값만 복사되는 문제 발생
  • 가리키는 대상 전체를 복사하는 방법은 얕은 복사(Shallow copy), 깊은 복사(Deep copy)를 통해 가능


얕은 복사

let user = {
  name: "nahyun",
  age: 25,
};

// for loop
let admin = {}
for (let key in user) {
    admin[key] = user[key]
}

// using Object
let admin = Object.assign({}, user)

// Spread Operator
let admin = { ...user } // {user.name, user.age}


얕은 복사의 문제점

let user = {
  name: "nahyun",
  age: 25,
  sizes: {
      height: 160,
      weight: 50
  }
};


let admin = Object.assign({}, user)

admin.sizes.weight++
--admin.sizes.height

// 얕은 복사의 문제점
console.log(admin.sizes.weight) //51
console.log(admin.sizes.height) //159
console.log(user.sizes.weight) //51
console.log(user.sizes.height) //159
  • 새로운 공간을 만드는 것
  • for loop
  • Object.assign()
  • Spread Operator
  • 객체 내 또 다른 객체가 있다면 복사되지 않는다.


깊은 복사

let user = {
  name: "nahyun",
  age: 25,
  sizes: {
      height: 160,
      weight: 50
  }
};

// stringify: js object > string, parse: string > js object
let admin = JSON.parse(JSON.stringify(user))

admin.sizes.weight++
--admin.sizes.height

// 얕은 복사의 문제점
console.log(admin.sizes.weight) //51
console.log(admin.sizes.height) //159
console.log(user.sizes.weight) //50
console.log(user.sizes.height) //160

  • 재귀 함수를 이용한 깊은 객체 복사
  • JSON 객체를 이용한 깊은 복사, stirngify는 객체를 문자열로 변환하는데 이때 원본 객체와의 참조가 끊긴다.



3. 형 변환

console.log(String(123)) //123
console.log(String(1/0)) //Infinity
console.log(String(-1/0)) //-Infinity
console.log(String(NaN)) //NaN
console.log(String(true)) //true
console.log(String(false)) //false
console.log(String(undefined)) //undefined
console.log(String("hello")) //hello

console.log(typeof String(123)) //string
console.log(typeof String(1/0)) //string
console.log(typeof String(-1/0)) //string
console.log(typeof String(NaN)) //string
console.log(typeof String(true)) //string
console.log(typeof String(false)) //string
console.log(typeof String(undefined)) //string
console.log(typeof String("hello")) //string

console.log(Number("")) //0
console.log(Number("123")) //123
console.log(Number("hello")) //NaN
console.log(Number("12hello")) //NaN
console.log(Number(true)) //1
console.log(Number(false)) //0
console.log(Number(null)) //0
console.log(Number(undefined)) //NaN

console.log(parseInt("123.123")) //123
console.log(parseFloat("123.123")) //123.123

console.log(Boolean("")) //false
console.log(Boolean("123")) //true
console.log(Boolean("hello")) //true
console.log(Boolean("12hello")) //true
console.log(Boolean(true)) //true
console.log(Boolean(false)) //false
console.log(Boolean(null)) //false
console.log(Boolean(undefined)) //false
  • 자바스크립트는 느슨한 타입 언어 혹은 동적 타입 언어로 변수의 자료형을 명시적으로 선언할 필요가 없는 언어
  • 연산자로 인한 계산이나 변수에 전달되는 값은 자동으로 암묵적 형 변환 수행
  • 강제적 형 변환을 위해서는 자료형 함수를 이용해 명시적 형 변환 수행
  • Number는 정수와 실수를 모두 포함하는 자료 형 변환이므로, 정수 혹은 실수의 명시적 변환은 parse 함수 사용
  • 정수 변환 : parseInt(피연산자), 실수 변환 : parseFloat(피연산자)



4. 산술대입 연산자

연산자

  • 프로그램에서 데이터를 처리하여 결과를 산출할 목적으로 사용되는 문자
  • 연산의 대상 값은 피연산자라고 하며, 피 연산자의 개수에 따라 단항/이항/삼항 연산자의 종류 존재
  • 단항 연산자 : 부호, 증감, 논리, 비트 연산자
  • 이항 연산자 : 산술, 대입, 비교, 논리 연산자
  • 삼항 연산자


산술 연산자

console.log(Boolean("")) //false
console.log(Boolean("123")) //true
console.log(Boolean("hello")) //true
console.log(Boolean("12hello")) //true
console.log(Boolean(true)) //true
console.log(Boolean(false)) //false
console.log(Boolean(null)) //false
console.log(Boolean(undefined)) //false
  • 수학적 계산을 위해 제공되는 연산자


대입 연산자

let num1 = 123
let num2 = 456
let str1 = "hello"
let str2 = "world"

let num3 = num1 + num2 //579
let str3 = str1 + str2 //helloworld

console.log(num3)
console.log(str3)
  • 계산한 결과를 하나의 변수에 저장하기 위한 연산자


복합 대입 연산자

let num = 10

let result1 = 30;
let result2 = 30;
let result3 = 30;
let result4 = 30;
let result5 = 30;

result1 += num //result1 = result1 + num
console.log(result1) //40
result2 -= num //result2 = result2 - num
console.log(result2) //20
result3 *= num //result3 = result3 + num
console.log(result3) //300
result4 /= num //result4 = result4 + num
console.log(result4) //3
result5 %= num //result5 = result5 + num
console.log(result5) //0
  • 산술 연산자로 피연산자를 계산해 결과값을 한번에 대입시켜주는 연산자


증가, 감소 연산자

let num = 10
let result = num++
console.log(result) //10
console.log(num) //11

let result2 = ++num
console.log(result2) //12
console.log(num) //12
  • 숫자 1만큼 증가시키거나 감소시킬 때 사용되는 연산자
  • 증가엽산자: ++(피연산자), (피연산자)++
  • 감소연산자: –(피연산자), (피연산자)–



5. 비교, 논리 연산자

비교 연산자

// 문자열 비교는 앞에서부터 비교, 앞이 동등하면 뒤를 비교
console.log('z' > 'a') //true
console.log('hello' < 'hi') //true
console.log('hello' >= 'helloo') // false

console.log('3' <= 30) //true
console.log(true == 1) //true
console.log(false != 123) //true
console.log(true === 1) //false
console.log(false !== 123) //true
  • 좌항과 우항의 피연산자를 비교한 다음 결과값을 논리적 자료형으로 반환하는 연산자
  • == 은 단순 값의 같음을 비교하는 동등 비교, === 는 자료형까지 같음을 판단하는 일치 비교 연산자
  • true, false 값으로 return


논리 연산자

console.log(true || false) //true
console.log(Boolean(0 || false)) //false
console.log(Boolean(123 || false)) //true
console.log(Boolean(123 && 0)) //false
console.log(Boolean(false && true)) //false
console.log(Boolean(true && 3)) //true
console.log(!false) //true
console.log(!123) //false
  • 좌항과 우항의 피연산자 간 논리 값을 연산하여 참 또는 거짓을 결과로 얻는 연산자
  • 논리 연산자 : &&(and), ||(or), !(not)



6. SCOPE

// global scope
let a = 1;
let b = 2;
let c = 3;

console.log(a); //1
console.log(b); //2

{
  // local scope
  let a = 3;
  let b = 4;
  let d = 5;
  console.log(a); //3
  console.log(b); //4
  console.log(c); //3
  {
      // 2-level local scope
      let a = 7
      let b = 8
      console.log(a) //7
      console.log(b) //8
  }
}

console.log(a); //1
console.log(b); //2
console.log(d); //ReferenceError: d is not defined
  • 변수 혹은 상수에 접근할 수 있는 범위
  • 모듈/함수 내 코드에서 동일한 변수 사용시 간섭을 줄이는 용도로 사용
  • Global Scope 와 Local Scope 타입으로 구분
  • Global Scope : 전역에 선언되어 어디에서도 접근 가능
  • Local Scope(block, function level scope) : 특정 지역에 선언되어, 해당 지역 내에서만 접근 가능
  • 다른 스코프에서는 같은 이름의 변수 선언 가능하다.
  • block : {}로 묶인 것
  • function level scope : 함수로 묶인 것



나의 회고 🤫

객체 복사에 대해 깊게 알 수 있어서 좋았다.
객체 복사를 할 때 요즘엔 항상 spread 연산자를 활용했는데 이게 얕은 복사였다는 것도 처음 알았다.
얕은 복사는 객체 내 또 다른 객체는 복사가 안된다는 것 잊지 말기!
reducer의 불변성에 다룰 때 얕은 복사 문제 때문에 immer가 나오게 된 것이 아닐까 하는 생각이 들었다. 이 부분은 조금 더 알아봐야 겠다!
앞으로는 객체 복사시 깊은 복사 방법인 JSON.parse 도 잘 활용해봐야겠다.