< Javascript > Koans 정리 (2/2)

초초·2023년 1월 4일
1

💻📚 TIL

목록 보기
12/22

내용정리

내 방식대로 이해한 내용/새로 알게된 것은 초록색으로 필기!

원시형 / 참조형

원시자료형

  • 값 자체에 대한 변형은 불가능
  • 원시 자료형을 변수에 할당할 경우, 값 자체가 할당됨
let variable = 'variable'; 
let variableCopy = 'variableCopy';  //3번재 줄 실행 'variable'
variableCopy = variable;   
variable = variableCopy;      	//변수 variable에 variableCopy 값을 할당
console.log(variable) 			// 'variable'

참조자료형

  • 참조 자료형의 데이터는 동적(dynamic)으로 변화
  • 참조 자료형을 변수에 할당할 경우, 데이터의 주소가 저장
const puppy = ['pinky', 'choco', 'brownie'];
let colored = puppy; //['pinky', 'choco', 'brownie']

puppy.push('milk'); // 
colored; // ['pinky', 'choco', 'brownie', 'milk']
puppy[1] = 'vanilla';
allowedToDrink[1] // 'vanilla'

참조자료형을 변수에 할당하면 변수는 주소값을 참조하여 원본 데이터에 접근하기 때문에 할당된 데이터의 요소를 변경하면 원본의 데이터도 변경됨

const person = {
  son: {
    age: 9,
  },
};
const boy = person.son;
boy.age = 20;

expect(person.son === { age: 20 }).to.equal(false);

person.son의 값은 {age: 20}이 맞지만 비교연산자로 비교되는 객체와 같은 주소값을 가지는지는 알 수 없기 때문에 false를 반환한다

배열

  • 배열의 타입은 object로 나온다
  • Array.isArray()로 배열인지 아닌지 확인이 가능
const emptyArr = [];
typeof emptyArr === 'array'   //false

 const multiTypeArr = [
      0,
      1,
      'two',
      function () {
        return 3;
      },
      { value1: 4, value2: 5 },
      [6, 7],
    ];
    
multiTypeArr[3]  // function () { return 3; }
multiTypeArr[3]()  // 3 -- 리턴값이 나옴

인덱스로 요소를 조회했을때 해당 인덱스의 요소가 함수면 함수를 그대로 출력하고, 해당 인덱스의 함수를 실행하면 리턴값이 나온다

const arr = [];
arr[0] = 1;
arr[1] = 2;
arr.push(3);

arr; // [1, 2, 3]
const poppedValue = arr.pop();  // 3 --잘려나온 값 반환
arr; // [1, 2]

slice()

  • arr.slice는 arr의 값을 복사하여 새로운 배열을 리턴
const arr = ['zero', 'one', 'two', 'three', 'four', 'five'];
const copiedArr = arr.slice();
copiedArr[3] = 'changed in copiedArr';

arr[3]		// 'three'
  • arr.slice(시작, 마지막) => 시작인덱스 요소 포함 ~ 마지막인덱스 이전 요소
const arr = ['peanut', 'butter', 'and', 'jelly'];

arr.slice(1)		// ['butter', 'and', 'jelly']
arr.slice(0, 2)		// ['peanut', 'butter']
arr.slice(2, 2)		// []
arr.slice(2, 20)	// ['and', 'jelly']);
arr.slice(3, 0)		// []

객체

const arr = [];
const emptyObj = {};
arr.length;				// 0
emptyObj.length;		// undefined;

빈 배열의 길이는 0 이지만, 빈 객체의 길이는 undefined 이다
빈 객체 뿐만이 아니라 객체의 경우 길이를 받고싶으면 키 혹은 값을 사용하여 길이를 조회할 수 있다 ex) Object.keys(obj).length 또한 속성값이 객체 안에 있는지 확인하고 싶으면 'key' in obj를 사용하여 반환받는 참/거짓 값으로 알 수 있다

const megalomaniac = {
      mastermind: 'Joker',
      henchwoman: 'Harley',
      getMembers: function () {
        return [this.mastermind, this.henchwoman];
      }
}
megalomaniac.getMembers()		// ['Joker','Harley']

객체의 속성값이 함수인 경우 obj,key()를 사용하여 함수를 사용할 수 있고 값은 함수의 리턴값이 된다

const currentYear = new Date().getFullYear();  //현재를 기준으로 년도를 불러옴

const megalomaniac = {
  	mastermind: 'James Wood',
  	henchman: 'Adam West',
  	birthYear: 1970,
  	calculateAge: function (currentYear) {
    	return currentYear - this.birthYear;
  	},
};
megalomaniac.calculateAge(currentYear)		//53

여기서 매서드 호출시, 매서드 내부에 쓰인 this는 해당 메서드를 호출한 객체megalomaniac를 말하게 된다

const obj = {
	mastermind: 'Joker',    
	henchwoman: 'Harley', 
	relations: ['Anarky', 'Duela Dent', 'Lucy'],
	twins: {
  		'Jared Leto': 'Suicide Squad',
  		'Joaquin Phoenix': 'Joker',
  		'Heath Ledger': 'The Dark Knight',
  		'Jack Nicholson': 'Tim Burton Batman',
	},
};
const copiedObj = Object.assign({}, obj);
delete obj.twins['Jared Leto'];
obj.henchwoman = 'Adam West';

copiedObj.henchwoman				// 'Harley'
'Jared Leto' in copiedObj.twins		// false

Object.assign()을 사용하여 변수 copiedObj는 빈 객체에 obj의 값을 복사해서 넣어주었기 때문에 객체 자체는 원본의 주소를 공유하지 않는 새로운 객체라고 볼 수 있다

Object.assign()

  • 첫번째 요소로 들어온 객체에 다음인자로 들어온 객체를 복사해서 넣어준다
    이때, 키가 겹치는 경우 다음인자를 우선으로 한다
const obj = {
  a: 1,
  b: {
    c: 2,
  },
};
const copiedObj = Object.assign({}, obj);
copiedObj.b.c = 3
---
obj === copiedObj // false
obj.b.c === copiedObj.b.c // true

하지만 객체 안의 요소의 값이 객체인 경우, 요소의 객체 자체의 주소값은 없어지지 않는 것처럼 보인다. 이를 얕은 복사라고 하는데, 따라서 객체 안에 객체가 있는 경우 예시의 number의 요소는 원본과 주소를 공유한다고 생각할 수 있다

얕은 복사란 객체를 복사할 때 위의 예제처럼 원래값과 복사된 값이 같은 참조를 가리키고있는 것을 말한다. 객체안에 객체가 있을 경우 한개의 객체라도 원본 객체를 참조하고 있다면 이를 얕은 복사라고 한다.
[참조]https://www.digitalocean.com/community/tutorials/copying-objects-in-javascript

spread 문법

  • ES6에서 새롭게 적용된 문법
  • 배열을 풀어서 인자로 전달하거나, 배열을 풀어서 각각의 요소로 넣을 때에 사용한다
const spread = [1, 2, 3];
const arr = [0, ...spread, 4];				//[0, 1, 2, 3, 4]

const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const concatenated = [...arr1, ...arr2];	//[0, 1, 2, 3, 4, 5] 
arr1.concat(arr2);							//[0, 1, 2, 3, 4, 5] 

spread는 한 배열 안에 두 번 사용할 수도 있으며 concat()과 같은 역할을 한다

const obj1 = {
      like: 'sleep',
      status: 'study',
    };

    const obj2 = {
      time: '03:40',
      todos: ['coplit', 'koans'],
    };
const merged = { ...obj1, ...obj2 };

console.log(merged.like === obj1.like);   //true

spread를 사용해 합친 두 객체의 요소는 같은 참조값을 공유하는 것을 확인할 수 있다
얕은복사 참조

rest 문법

  • 파라미터를 배열의 형태로 받아서 사용할 수 있음
  • 파라미터의 개수가 가변적일 때 유용
function returnFirstArg(firstArg) {
      return firstArg;
}
returnFirstArg('first', 'second', 'third') 	//'first', 'second', 'third'

function returnSecondArg(firstArg, secondArg) {
      return secondArg;
}
returnSecondArg('only give first arg')		//undefined

함수의 매개변수가 두 개일때 전달인자가 하나뿐이고 두번째 매개변수를 리턴하면 undefined를 출력한다

Argument

  • argument는 배열 형태의 객체이다
function getAllParamsByRestParameter(...args) {
      return args;
    }
function getAllParamsByArgumentsObj() {
      return arguments;
    }

const restParams = getAllParamsByRestParameter('first', 'second', 'third');
const argumentsObj = getAllParamsByArgumentsObj('first', 'second', 'third');

restParams === argumentsObj			// false
typeof restParams					// 'object'
typeof argumentsObj					// 'object'
Array.isArray(restParams)			// true
Array.isArray(argumentsObj)			// false

두 변수는 형태는 같게 생겼지만 다른 값으로 취급된다 arguments 객체를 이용해 만든 argumentsObj의 경우 배열 형태를 하고 있는 객체이다

Object.keys(argumentsObj)			// ['0', '1', '2']
Object.values(argumentsObj)			// ['first', 'second', 'third']

arguments 객체는 Object.keys(),Object.values(argumentsObj)를 이용하여 키를 인덱스, 값을 배열 요소로 갖는 객체임을 확인할 수 있다

function getAllParams(required1, required2, ...args) {
      return [required1, required2, args];
}
getAllParams(123) 			// [123, undefined, []

...args 는 배열의 형태로 매개변수를 받기 때문에 전달인자가 없을 경우 빈 배열[]을 반환한다

구조분해할당

  • 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 표현식
const array = ['apple', 'mango', 'lemon', 'banana']
const [first, second] = array

console.log(first) 			//'apple'
console.log(second)			//'mango'

const array = ['apple', 'mango', 'lemon', 'banana']
const [start, ...rest] = array
console.log(start)			//'apple'
console.log(rest)			// ['mango', 'lemon', 'banana']

spread/rest 문법을 사용하여 배열을 분해할때 ...rest로 분해된 요소가 배열로 리턴되는 것을 주의해야 한다

단축문법

  1. 기본적인 구조 분해 할당
const name = '가나다'
const age = 20

const person = {
    name,
    age,
    level: 'Junior',
}
    
person = {name: '가나다', age: 20, level: 'Junior'}
  1. spread 문법으로 나머지 객체 받아오기
const dog = { name: '콩이', sound: '멍멍' }
const { name, ...args } = dog

console.log(name)		// '콩이'
console.log(args)		// {sound: '멍멍'}
  1. 객체 덮어쓰기
const user = {
      name: '김',
      company: {
        name: 'N Inc',
        department: 'Design',
        role: {
          name: 'Web designer'
        }
      },
      age: 28
    }

//1번 --- 유저 내용을 앞에 미리 둠
const changedUser = {
  	...user,
 	 name: '박',
 	 age: 24
}
//2번  --- 유저 내용을 뒤에 들고 옴 
const overwriteChanges = {
	  name: '박',
 	 age: 25,
	  ...user
}
//3번
const changedDepartment = {
 	 ...user,
 	 company: {
  	 	 ...user.company,
   		 department: 'Marketing'
 	 }
}

출력결과

//1번
expect(changedUser).to.eql({
  name: '박',
  company: {
        name: 'N Inc',
        department: 'Design',
        role: {
          name: 'Web designer'
    	}
  },
  age: 24
})
//2번
expect(overwriteChanges).to.eql({
  name: '김',
  company: {
    	name: 'N Inc',
        department: 'Design',
        role: {
          name: 'Web designer'
    	}
  },
  age: 28
})
//3번
expect(changedDepartment).to.eql({
  name: '김',
  company: {
    	name: 'N Inc',
        department: ''Marketing'',
        role: {
          name: 'Web designer'
    	}
  },
  age: 28
})

순서에 따라 덮어 씌우는 값이 바뀌니까 잘 확인하기 !

profile
잔디 꽉꽉 심쟈 🍀

0개의 댓글