(블로깅) D+13 Javascript Koans 정리 및 회고

JulyK9·2022년 7월 13일
0

부족함을 많이 느끼는 하루다
기본적인 것들에 대한 이해가 불확실하면
코드의 작은 변화에도 결과가 많이 달라지는 것을 보게 된다.

그래도 계속 반복해서 이해하려고 노력하면
그렇게 안하는 것보다 나아질 것이라는 믿음은 확실하다.

계속 혼동하는 부분

원시 자료형을 변수에 할당할 경우, 값 자체의 복사가 일어남

let overTwenty = true;
let allowedToDrink = overTwenty;

overTwenty = false;
console.log(overTwenty)  // false
console.log(allowedToDrink)  // true [계속 혼동됨]

=> 2번째 줄에서 allowedToDrink 변수에 값 자체(true)가 할당됨
=> 원시자료형은 스택에 공간이 마련되고 그 안에 값이 저장되잖아
=> overTwenty 와 allowedToDrink 변수의 공간은 스택에 따로 마련되고
=> 그 안의 값은 각각 true 였으므로
=> overTwenty 변수에 false 가 재할당된다 하더라도
=> allowedToDrink 변수 공간의 값인 true 는 그대로 유지된 상태임

let currentYear = 2020;
function afterTenYears(year) {
	year = year + 10;
}

console.log(afterTenYears()); // 함수에 return 이 없으니까 undefined
console.log(afterTenYears()); // return이 있는 경우, NaN (인자 없이 호출해서 year는 undefined, 이 상태에서 연산을 했으므로)
afterTenYears(currentYear); // 아무것도 없음 (인자가 전달됐지만 return이 없기 때문)
afterTenYears(currentYear); // return이 있는 경우, 2030
console.log(currentYear); // 2020

function afterTenYears2(currentYear) {
	currentYear = currentYear + 10; // 함수 스코프안에서 인자로 전달된 지역변수에 새로운 값을 할당, 전역변수에 영향 없음
  	console.log(currentYear); // 2030 (함수 안에서 지역변수 currentYear 호출) 
  	return currentYear;
  	console.log(currentYear); // (return 으로 함수의 생명이 끝나서 아무것도 안나옴???)
}

let after10 = afterTenYears2(currentYear);
console.log(currentYear);  // 2020 (전역변수의 값 출력, 상단에서 함수에 의해 영향받은 부분이 없음)
console.log(after10);   // 2030, 리턴된 값이 할당된 변수를 출력

=> 함수의 인자를 전달하는 행위는 매개변수에 자료를 할당하는 것임
=> 함수 호출 => 전달 인자가 호출된 함수의 스코프 내에서 지역 변수가 되며 (매 호출 시마다) 새롭게 선언됨

함수 선언식과 함수 표현식의 차이

  • 함수 선언식은 호이스팅 되지만, 함수 표현식은 호이스팅 되지 않음

원시 자료형과 참조 자료형 변수 할당의 차이

const pi = 3.14
const arr = ["hello", "world", "code", "states"];

=> 원시 자료형은 변수에 값이 할당되고
=> 참조 자료형은 변수에 주소가 할당됨(실제 데이터가 저장된 주소를 가리킴)
=> 왜냐면 참조 자료형은 데이터가 동적으로 변함(mutable)
=> 따라서 데이터는 특별한 저장공간(heap)에 저장하고 변수에는 저장 공간의 주소를 할당

배열 전체 복사

  • arr.slice() 또는 arr.slice(0); (얕은복사)
  • 복사한 배열은 다른 주소값을 참조함에 유의

배열 요소 추가 메서드도 반환되는 값이 있다!

  • arr.pop(), arr.shift() : '제거된 요소의 값'이 리턴됨
  • arr.push(), arr.unshift() : '더해지고 난 길이값'이 리턴됨
    => 이 메서드 들은 모두 원본 배열을 직접 변경하는 mutable 메서드

참조자료형 안의 참조자료형 케이스

  • 참조자료형 안의 참조자료형은 여전히 힙에 저장되므로 같은 주소값을 공유하도록 복사됨(얕은복사)
  • 개인적으로 값을 확인하면서 해본 부분
let character = {
  name: 'Jane',
  racial: 'elf',
  size: {
  	weight: 50,
    tall: 170,
  }
}


let copyCharacter = Object.assign({}, character);
// 복제된 새로운 객체를 변수에 할당, 새로운 주소값이 부여됨

character.size === copyCharacter.size
// true
// 참조자료형 안의 참조자료형은 같은 주소값을 공유함

character.name === copyCharacter.name
// true
// 참조자료형 안의 원시자료형도 같은 주소값을 공유함??
// 뭔가 좀 이상한데..?

character
copyCharacter
character === copyCharacter // 객체의 요소들이 같지만 참조하는 주소값이 다르므로 false

delete character['size']['tall'];
character
copyCharacter
// 원본 객체의 참조자료형과 복제된 객체의 참조자료형이 같은 주소를 공유하므로
// 원본 객체의 내부 객체를 삭제한 결과가 복제한 객체에도 적용됨   

delete character['name'];
// 원본 객체안의 원시자료형인 name 속성 삭제함
character
copyCharacter
// 원본 객체에서만 삭제되고
// 복제된 객체는 삭제되지 않음
// 근데 왜 위에서는 같은 주소값을 공유하는 거 같지???

렉시컬 스코프와 클로저 관련

let age = 27;
let name = 'jin';
let height = 179;

function outerFn() {
   let age = 24;         // 3. age = 26 으로 재할당됨 // outer 함수 스코프내에서 let으로 age 를 선언해주고 있으므로 외부 스코프를 참조하지 않음 
   name = 'jimin';       // 3. outer 함수 내애서 name 이 선언된 바 없기 때문에 상위 스코프, 외부 스코프 변수에 값을 재할당 하므로 전역의 name 이 jimin이 됨
   let height = 178;

   function innerFn() {  // 2. inner 함수가 실행되면
     age = 26;           // 3. inner 함수 안에서 선언되지 않았으므로 바로 상위 스코프의 age 값이 26으로 재할당됨
     let name = 'suga';  
     return height;      // 4. height 가 inner 함수 스코프에 없으므로 바로 상위 스코프, 외부 함수의 지역 변수에 접근하여 178를 리턴함
   }

   innerFn();   // 1. 먼저 inner 함수가 호출(실행)됨

   expect(age).to.equal(26);   // 5. 현재 평가하는 위치는 outer 함수의 스코프 인데 age 가 26으로 재할당되었으므로 26임
   expect(name).to.equal('jimin');  // 6. outer 함수 스코프에서 name은 'jimin'으로 할당되고 있음

   return innerFn; // 내부함수명을 적어서 리턴한다고 한거 같은데 맞나???  
}

const innerFn1 = outerFn(); // 변수명은 내부 함수와는 관련이 없는 것 바꿔도 상관없음, outer 함수의 리턴값을 가져오기 위한 방법
    // innerFn();   178
    // outerFn()()  178 이걸 생각하면 좀 더 이해가 됨
    // 이렇게 설계하는 이유는 클로저 함수(내부함수)를 전역 스코프에서 접근해서 호출할 수가 없기 때문
    // 외부함수가 내부함수를 리턴하도록 하고, 전역에서 외부함수의 리턴값을 변수에 할당한 뒤, 변수를 사용하여 호출하면 전역 스코프에서 내부 함수의 호출이 가능하게 됨

expect(age).to.equal(27);  // 현재 스코프는 전역, 전역의 age 변수는 재할당 된 바 없으므로 그대로 27
expect(name).to.equal('jimin');  // 3. outer 함수 내애서 name 이 선언된 바 없기 때문에 상위 스코프, 외부 스코프 변수에 값을 재할당 하므로 전역의 name 이 jimin이 됨
expect(innerFn()).to.equal(178);

추가로 공부할 부분

this

커링

Object.assign()

  • 객체를 복사할 때 쓰는 방법
  • 빈 배열을 앞 인자에 넣어서 복사하는 효과 Object.assign({}, obj);

깊은 복사와 얕은 복사

동기님의 좋은 설명


왤케 내용이 없어졌나 했더만..어제 작성했던 자료들이 다 날라갔다..ㅜ.ㅜ
어제 제목이랑 내용까지 들어간거 확인하고 블로깅 페이지에 주소까지 붙였는데 왜 다 날아갔는지..
기록을 얼마나 남겼다는 것이 중요한 거라기보다
정리하면서 얼마나 내 것이 되었는지가 중요한거라고 위로를 해본다 ㅠ
주말에 복습하면서 조금씩 다시 정리해야겠다..

profile
느리지만 꾸준하게. 부족하거나 잘못된 부분은 알려주시면 감사하겠습니다.

0개의 댓글