본문 바로가기
  • 사람은 무언가를 배울 필요가 있을때가 되서야 비로소 배우게 된다.
JavaScript

JavaScript 데이터

by YoHaYo 2023. 6. 19.
728x90
반응형

Part 3. JavaScript Level up

 

Ch 1. JS 데이터

01. 문자

 

리터럴(Literal)이란?

리터럴은 데이터(값) 그 자체를 뜻한다. 즉, 변수에 넣는 변하지 않는 데이터를 의미하는 것.

const a = 1;

여기서 a는 상수이고, 1은 리터럴이다.

 

리터럴 표기법이란?

코드 상에서 데이터를 표현하는 방식을 리터럴이라 하고, 객체지향언어에서는 객체의 리터럴 표기법을 지원한다.

리터럴표기법이란, 변수를 선언함과 동시에 그 값을 지정해주는 표기법을 말한다.

 

//리터럴 표기법

var no = 3;

var obj = { name: 'JY', age: 20 }; // 객체리터럴 방식으로 만든 객체

 

const str = '0123'

 

console.log(str) // 0123

console.log(str.length) // 4

console.log('0123'.length) // 4

console.log('0123 '.length) // 5

 

const str1 = 'The quick brown fox jumps'

 

console.log(str1.indexOf('fox')) // 16

console.log(str1.indexOf('rabbit') !==-1) // false

 

// slice(x,y) : x번째부터 y-1까지 추출

console.log(str1.slice(0, 3)) // the

 

// replace(x,y) : x를 y로 교체

console.log(str1.replace('brown', 'red')) // The quick red fox jumps

console.log(str1.replace('brown', '')) // The quick fox jumps

 

// match 매소드로 정규표현식으로 이메일 아이디 추출

// 지금은 정규표현식이 뭔지는 알필요없당

const str2 = 'brownfox@gmail.com'

console.log(str2.match(/.+(?=@)/)[0]) // brownfox

 

// trim : 공백문자 제거

const str3 = '   brownfox'

console.log(str3.trim()) // brownfox

 

 

 

02. 숫자와 수학 

숫자

const pi = 3.14159265358979

console.log(pi)

 

// toFixed(2) : 소수점 2자리까지 남기고 나머지 제거

const str = pi.toFixed (2) // 3.14

console.log(str)

// toFixed : 문자데이터로 반환됨.

console.log(typeof str) //string

 

// parseInt : 정수로 반환

const integer = parseInt(str)

// float : 실수로 변환

const float = parseFloat(str)

console.log(integer) // 3

console.log(float) // 3.14

console.log(typeof integer, typeof float) // number number

 

수학

console.log('abs:', Math.abs(-12)) // 12

 

console.log('min:', Math.min(2, 8)) // 2

 

console.log('max:', Math.max(2, 8)) // 8

 

// ceil : 올림

console.log('ceil:', Math.ceil(3.14)) // 4

// floor : 내림

console.log('floor:', Math.floor(3.14)) // 3

// round : 반올림

console.log('round:', Math.round(3.14)) // 3

 

console.log('random:', Math.random())

 

03. 배열(1) 

const numbers = [1, 2, 3, 4]

const fruits = ['Apple', 'Banana', 'Cherry']

 

// .length : 아이템 개수가 몇개 들어있는지 출력

 

console.log(numbers[1]) // 2

console.log(fruits[2]) //Cherry

 

console.log(numbers.length) // 4

console.log(fruits.length) // 3

console.log([1, 2].length) // 2

console.log([].length) // 0

console.log('---')

 

// .concat() : 2개의 배열 데이터를 병합. 원본의 배열 데이터를 수정하는것이 아님.

 

console.log(numbers.concat(fruits))

console.log(numbers)

console.log(fruits)

console.log('---')

 

// .forEach() : 아이템의 개수만큼 콜백을 각각 반복 실행

fruits.forEach(function(element, index, array) {

  console.log(element, index, array)

})

console.log('---')

 

// .map() : 콜백으로 반환된 데이터를 배열로 만들어줌

const a = fruits.forEach((fruit, index) => { // this 키워드가 없으므로 화살표 함수를 써도됨.

  console.log(`${fruit}-${index}`)

})

console.log(a)

 

const b = fruits.map(function (fruit, index) {

  return `${fruit}-${index}`

})

console.log(b)

 

const c = fruits.map((fruit, index) =>({

    id : index,

    name : fruit

  }))

console.log(c)

console.log('---')

 

04. 배열(2)

const numbers = [1, 2, 3, 4]

const fruits = ['Apple', 'Banana', 'Cherry']

 

const a = numbers.map(number => number < 3)

console.log(a)

 

// .filter() : 말그대로 조건을 만족하는 데이터만 걸러줌.

// true만 배열로 만들어줌

const b = numbers.filter(number => number < 3)

console.log(b)

console.log(numbers) // filter는 원본 배열에 손상을 주지않는다.

 

// .find() : 아이템 찾기

const c = fruits.find(fruit => /^B/.test(fruit))

  // ^B : 정규표현식. B로 시작하는 것이라는 의미

console.log(c)

 

// .findIndex() : 찾는 아이템의 인덱스 번호 반환

const d = fruits.findIndex(fruit => /^C/.test(fruit))

  // ^B : 정규표현식. B로 시작하는 것이라는 의미

console.log(d)

 

// .includes() : 인수로 사용되는 데이터가 포함되어 있는지 확인

const e = numbers.includes(3)

console.log(e)

 

const f = fruits.includes('HEROPY')

console.log(f)

 

// .push()  : 배열에 가장 뒤쪽에 데이터 삽입

// .unshift() : 배열에 가장 앞쪽에 데이터 삽입

// 원본 수정됨 주의!

numbers.push(5)

console.log(numbers)

 

numbers.unshift(0)

console.log(numbers)

 

// .reverse() : 배열의 순서를 거꾸로 바꿈

// 원본 수정됨 주의!

numbers.reverse()

fruits.reverse()

 

console.log(numbers)

console.log(fruits)

 

// .splice() : ?번째 인덱스 아이템 지우기

// 원본 수정됨 주의!

const numbers1 = [1, 2, 3, 4]

// 인덱스번호 2(3번째)부터 아이템에서 2개 지우기

numbers1.splice(2, 2) // [1, 2]

console.log(numbers1)

 

const numbers2 = [1, 2, 3, 4]

// 아래처럼 쓰면 데이터 끼워넣기가 가능 !

numbers2.splice(2, 0, 999) // [1, 2, 999, 3, 4]

console.log(numbers2)

 

 

 

05. 객체

 

// Object.assing()

 

const userAge = {

  // key: value

  name: 'Heropy',

  age: 85

}

 

const userEmail = {

  name: 'Heropy',

  email: 'thesecon@gmail.com'

}

// assing(x, y) : x가 y로 덮어쓰이게 됨. 그 덮어 쓰인 객체가 target으로 반환됨.

const target = Object.assign(userAge, userEmail)

console.log(target)

console.log(userAge)

// target, userAge 는 같은 메모리 주소를 갖기 때문에 true

console.log(target === userAge) // true

 

const a = {k: 123 }

const b = {k: 123 }

console.log(a, b)

// a, b는 다른 메모리 주소를 갖기 때문에 false

console.log(a === b) // false .

 

 

// Object.assing()

 

const user = {

  name: 'Heropy',

  age: 85,

  email: 'thesecon@gmail.com'

}

 

const keys = Object.keys(user)

console.log(keys) //  ['name', 'age', 'email']

 

// key의 이름을 입력해서 데이터를 가져옴

console.log(user['email']) // thesecon@gmail.com

 

const values = keys.map(key => user[key])

console.log(values) // ['Heropy', 85, 'thesecon@gmail.com']

 

06. 구조 분해 할당

// 구조 분해 할당 (Destructuring assignment)

// 비구조화 할당

const user = {

  name: 'Heropy',

  age: 85,

  email: 'thesecon@gmail.com'

}

 

// 아래에서 지정한 것은 기본값임. 위에 함수내에 정의가 안됬을때 출력하는값.

const { name: Heropy, age, email, address = 'Korea' } = user

// E.g, user.address

console.log(`사용자의 이름은 ${Heropy}입니다.`)

console.log(`${Heropy}의 나이는 ${age}세 입니다.`)

console.log(`${Heropy}의 이메일 주소는 ${email}입니다.`)

console.log(address)

 

const fruits = ['Apple', 'Banana', 'Cherry']

const [a, b, c, d] = fruits

console.log(a, b, c, d) // Apple Banana Cherry undefined

const [, , c1] = fruits

console.log(c1) // Cherry

 

07. 전개 연산자

 

// 전개연산자(Spread) : ... 사용. 쉼표로 구분된 각각의 아이템으로 배열데이터가 전개되서 만들어짐.

 

const fruits = ['Apple', 'Banana', 'Cherry', 'Orange']

console.log(fruits) //  ['Apple', 'Banana', 'Cherry']

console.log(...fruits) // Apple Banana Cherry

// console.log('Apple', 'Banana', 'Cherry')

 

function toObject(a, b, ...c) {

  // 이때 ...c를 나머지 매개변수라하고 나머지 아이템을 싹 가져온다.

  // c에는  'Cherry', 'Orange'가 배열로 출력됨

  return {

    a, // 속상: 변수 -> a: a 로 같으면 a 하나만 남겨도됨.

    b: b,

    c: c

  }

}

console.log(toObject(...fruits))

 

// 전개 연산자 축약형으로 쓰기

const toObject = (a, b, ...c) => ({a, b, c})

 

08. 불변성

원시 데이터 : String, Number, Boolean, undefined, null

참조형 데이터 : Object, Array, Function

메모리 주소 1 메모리 주소 2 메모리 주소 3 메모리 주소 4

 

단순히 a, b 가 1로 같아서 true 인것이 아니라. a와 b가 같은 메모리 주소에 저장되서 그렇다. 

a = 7로 재할당 하게 되면, 3번 메모리 주소에 a = 7이 들어간다. 때문에 a와 b가 바라보는 메모리 주소가 달라서 false가 나온다. 

let c = 1로 할당했을때부터 데이터 불변성을 알 수 있다.

c = 1로 할당하면 4번 메모리 주소로 c = 1 들어가는게 아니라 기존의 1번 메모리 주소로 할당되게 된다. 

즉, 원시 데이터 들은 불변한다. 이를 데이터 불변성이라고 한다. 

원시 데이터들은 어렵게 생각할것없이 생긴게 다르면 서로 다른 데이터라 보면된다.

 

그러나 참조형 데이터들은 생긴게 같아도 다를 수 도 있다. 

그럼 이제 참조형 데이터들은 어떻게 메모리를 사용하는지 알아보자.

 

a 와 b 는 모두 속성k에 데이터 1들어 있다. 그러나 a,b는 메모리 주소를 1,2로 다른 곳을 바라본다. 그러므로 false값이 출력된다.

 

참조형 데이터는 원시형 데이터와 다르게 새로운 값을 만들때마다 새로운 메모리 주소를 할당 받는다는 특성을 가지고 있다.

 

※ 주의할것.

b=a로 같은 메모리 주소를 바라보게 한 뒤

a.k = 2로 a 의 데이터를 2로 바꾸게 되면 의도치 않게 같은 메모리를 바라보고 있는 b까지 2로 바뀐다.

이것 때문에 복잡하게 데이터를 처리하는 웹사이트를 만들때 의도치 않게 다른곳이 수정되는 오류가 매우 빈번하게 발생된다.

09. 얕은 복사와 깊은 복사

const copyUser = Object.assing({}. user)

const copyUser = {...user}

로 새로운 메모리 주소로 할당시킨다. 그렇게 하면 user와 copyUser의 데이터를 다르게 관리 할 수 있다. 이를 ‘얕은 복사’ 라고 한다.

 

깊은 복사는 순수 js 로직으로는 구현이 귀찮다. lodash를 이용하면 _.cloneDeep 구문으로 쉽게 구현 가능하다.

import _ from 'lodash'

// 얕은 복사(Shallow copy), 깊은 복사(Deep copy)

 

// 얕은 복사: 객체 내부의 값(Primitive value)은 복사하지만, 객체의 레퍼런스(참조값)는 복사하지 않는 것을 말합니다.

// 깊은 복사: 객체 내부의 값과 레퍼런스(참조값) 모두 복사하는 것을 말합니다.

const user = {

  name: 'Heropy',

  age: 85,

  emails: ['thesecon@gmail.com']

}

const copyUser = _.cloneDeep(user) // lodash로 깊은 복사 구현

 

console.log(copyUser === user)

user.age = 22

console.log('user', user)

console.log('copyUser', copyUser)

 

console.log('-----')

 

user.emails.push('neo@zillinks.com')

console.log(user.emails === copyUser.emails)

console.log('user', user)

console.log('copyUser', copyUser)

 

결론 

참조형 데이터를 복사할때, 얕은 복사로도 충분히 복사가 가능하다면 
const copyUser = Object.assing({}. user)
const copyUser = {...user}
구문으로 얕은 복사를 하면되고,
만약에 참조형 데이터 내부에 또 다른 참조형 데이터를 들고 있다면 
lodash 패키지의 도움을 받아 _.cloneDeep 구문으로 깊은 복사를 해주면 된다.
반응형

댓글