내 방식대로 이해한 내용/새로 알게된 것은 초록색으로 필기!
let variable = 'variable';
let variableCopy = 'variableCopy'; //3번재 줄 실행 'variable'
variableCopy = variable;
variable = variableCopy; //변수 variable에 variableCopy 값을 할당
console.log(variable) // 'variable'
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를 반환한다
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]
const arr = ['zero', 'one', 'two', 'three', 'four', 'five'];
const copiedArr = arr.slice();
copiedArr[3] = 'changed in copiedArr';
arr[3] // 'three'
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의 값을 복사해서 넣어주었기 때문에 객체 자체는 원본의 주소를 공유하지 않는 새로운 객체라고 볼 수 있다
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
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를 사용해 합친 두 객체의 요소는 같은 참조값을 공유하는 것을 확인할 수 있다
얕은복사 참조
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를 출력한다
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로 분해된 요소가 배열로 리턴되는 것을 주의해야 한다
const name = '가나다'
const age = 20
const person = {
name,
age,
level: 'Junior',
}
person = {name: '가나다', age: 20, level: 'Junior'}
const dog = { name: '콩이', sound: '멍멍' }
const { name, ...args } = dog
console.log(name) // '콩이'
console.log(args) // {sound: '멍멍'}
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
})
순서에 따라 덮어 씌우는 값이 바뀌니까 잘 확인하기 !