주구장창 적으면서 복습한다...!✍🏻✍🏻✍🏻
이번엔 옛---날에 배워서 까먹을 만한 것들 위주로.
Ah, 다음 편은 언더바 꼼꼼하게 Part.2 까지 복습한다.
초기에 올렸던 언더바는 좀 실수도 있고, 아쉬운 부분이 많다.

1. Object

객체의 내부를 먼저 구성하고 할당하는 방식으로 만들어본다.
뭔가 복잡해보일 수 있지만, 결과부터 보면 간단한 구성이다.

// 1. Object
let address = '부산'
let members = {};

let addFamily = function(age, name, role) {
  this.members[role] = { age, name };
}
let getHeadCount = function() {
  return Object.keys(this.members).length;
}

const family = { address, members, addFamily, getHeadCount }

family.addFamily(22, '짱구', '본인')
family.addFamily(3, '짱아', '동생');
family.addFamily(5, '흰둥이', '강아지');
console.log('가족 수 : ' + family.getHeadCount())
console.log(members)

// 가족 수 : 3
// { '본인': { age: 22, name: '짱구' },
//   '동생': { age: 3, name: '짱아' },
//   '강아지': { age: 5, name: '흰둥이' } }

2. scope

살-짝 헷갈리는 문제다.
log2에서 log을 실행하면 log2안에서 실행될 것 같지만
밖에서 실행한 결과로 출력된다.

// 2. scope

var A = "글로벌";

function log() {
    console.log(A);
}

function log2() {
    var A = "로컬";
    log();
}

log();  // 글로벌
log2(); // 글로벌

3. closure

함수 안에 count를 숨겨놓고, 인스턴스 메소드로 접근하는 방식이다.

// closure
function Counter() {
  let count = 0;

  return {
    addCount() {
      count++;
      console.log('count : ' + count);
    },
    subCount() {
      count--;
      console.log('count : ' + count);
    },
    showCount() {
      console.log('count : ' + count);
    }
  }
}

const c = new Counter();
c.addCount();  // count : 1
c.addCount();  // count : 2
c.addCount();  // count : 3
c.subCount();  // count : 2
c.showCount(); // count : 2

4. prototype

생성자에서 prototype을 이용하여 객체를 생성하고 상속도 해본다.
주석에다 설명하는게 더 보기 좋을 것 같다...!

// prototype
// 1. 생성자 함수
function List() {
  this.list = {};
}

// 2. prototype에 put 메소드 추가
List.prototype.put = function(key, user) {
  this.list[key] = user;
}

// 3. prototype에 getData 메소드 추가
List.prototype.getUser = function(key) {
  return this.list[key];
}

// 4. productList 인스턴스 생성
const userList = new List();
userList.put('1', { name: '다현', age: 22 });
console.log(userList.getUser('1')); // { name: '다현', age: 22 }

// 5. List를 호출하여 this를 전달. DeleteList에 list가 추가됨.
function DeleteList() {
  List.call(this);
}

// 6. List의 prototype을 DeleteListdml prototype에 연결. (상속)
DeleteList.prototype = Object.create(List.prototype)
DeleteList.prototype.deleteUser = function() {
  this.list = {};
};
const deleteUserList = new DeleteList();

deleteUserList.put('2', { name: '소희', age: 27 });
console.log(deleteUserList.getUser('2')); // { name: '소희', age: 27 }

deleteUserList.deleteUser();
console.log(deleteUserList.getUser('2')); // undefined

5. this

this는 다양하게 사용해 보는 게 더 익숙해진다.

// this
// name, price, function을 갖는 객체를 선언한다.
const product = {
  name: '에어팟',
  price: 219000,
  getVAT() {
    return `세금 : ${this.price / 10}원`;
  }
}
const valueOfProduct = product.getVAT();
console.log(valueOfProduct); // 세금 : 21900원

const calVAT = product.getVAT;
const VAT = calVAT();
console.log(VAT); // NaN원

const counter1 = {
  count: 0,
  addAfter1Sec() {
    setTimeout(function() {
      this.count++;
      console.log(this.count);
    }, 1000)
  }
};

counter1.addAfter1Sec(); // NaN
// this를 메소드 안에서 정의했지만 메소드를 다른 변수에 저장하고 그 변수를 통해 호출하면 this는 전역 객체를 가리킨다.
// 호출하는 시점에 . 연산자와 함께 객체가 주어져야 메소드 안의 this가 호출의 주체인 객체가 된다.

const counter2 = {
  count: 0,
  addAfter2Sec() {
      setTimeout(() => {
          this.count += 1;
          console.log(this.count);
      }, 2000)
  }
};
counter2.addAfter2Sec(); // 1