// Objects
// one of the JavaScript's data types.
// a collection of related data and/or functionality.
// Nearly all objects in Javascripts are instances of Object
// object = { key : value };

// 1. Literals and properties
const obj1 = {}; //'object literal' syntax
const obj2 = new Object(); // 'object constructor' syntax

function print(person) {
    console.log(person.name);
    console.log(person.age);
}

const ellie = {name : 'ellie', age: 4};
print(ellie);

ellie.hasJob = true; // 뒤에서 정의해 놓지도 않는 것을 추가할 수 있다.
                    // dynamin type language,. Runtime 때 형이 결정
console.log(ellie.hasJob); // true

//can delete properties later
delete ellie.hasJob;

console.log(ellie.hasJob); // undefined 출력 된다.

// 2. Computed properties
// key should be always string
console.log(ellie.name); // 코딩하는 그 순간 key의 값을 받아오고 싶을 때
console.log(ellie['name']); // 코딩하는 시점에 어떤 key가 필요한지 모를 때, runtime에서 결정 될 때

ellie['hasJob'] = true;
console.log(ellie.hasJob);

function printValue(obj, key) {
    console.log(obj.key); // undefined
    console.log(obj[key]); // ellie 출력
}

printValue(ellie, 'name');
printValue(ellie, 'age');

// 3. Property value shorthand
const person1 = { name: 'bob', age : 2 };
const person2 = { name: 'steve', age : 3 };
const person3 = { name: 'dave', age : 4 };
const person4 = { name: 'malza', age : 30 };
//어떻게 빠르게 할까?

const person5 = makePerson('wow!!', 100);
console.log(person5.name, person5.age);

function makePerson(name, age) {
    return {
        name: name, //key 와 valye 의 이름이 동일하다면 생력할 수 있다.
        age
    };
}

// 4. Constructor function
// 다른 계산을 하지 않고 순수하게 Object를 생성하는 함수들은 보통 대문자로 시작한다.
// 위의 makePerson 을 바꿔보면
function Person(name, age) {
    //생략된 것들
    // this = {};
        this.name = name;
        this.age = age;    
    // return this;
}

// class 에서 object를 만드는 것처럼 사용할 수 있다.
const Person6 = new Person('Person', 200);
console.log(Person6);

// 5. in operator: property existence check (key in obj)
// 해당하는 object 안에 key 가 있는지 없는지 확인
console.log('name' in ellie);
console.log('age  ' in ellie); //공백있어서 다르면 false 출력
console.log('what?' in ellie); //false 출력
console.log('age' in ellie);

// 6. for..in vs for..of
// for (key in obj)
//console.clear(); //이전 출력 삭제
for (key in ellie) {  // ellie 안에 있는 key들을 출력해줘~
    console.log(key);
}

// for (value of iterable)
const array = [1, 2, 4, 5];
//우리가 알고 있는 for문
for(let i = 0; i < array.length; i++)
{
    console.log(array[i]);
}

//다음과 같이 쉽게 가능
for(value of array) {
    console.log(value);
}
console.clear();
// 7. Fun cloning
// Object.assign(dest, [obj1,obj2, obj3....])
const user = { name: 'ellie', age: '20'};
const user2 = user;
user2.name = 'coder'; // 둘이 같은 곳을 참조 하고 있기 때문에 바뀐다.

console.log(user);
console.log(user2);

// old way
const user3 = {};
for(key in user){
    user3[key] = user[key];
}

console.log(user3);

// new way
const user4 = {};
Object.assign(user4, user);``
console.log(user4);

//or
const user5 = Object.assign({}, user);
console.log(user5);

// another example
const fruit1 = { color: 'red'};
const fruit2 = { color: 'blue', size: 'big'};
const mixed = Object.assign({}, fruit1, fruit2);
console.log(mixed.color);
console.log(mixed.size); // blue 와 big 으로 덮여 쓰여진다.
method: 객체 프로퍼티로 할당 된 함수

화살표 함수는 일반 함수와는 달리 자신만의 this 를 가지지 않는다.
화살표 함수 내부에서 this를 사용하면, 그 this 는 외부에서 값을 가져온다.

브라우저 환경에서 this가 가져오는 전역객체는 window,
Node.js 는 global이다.

let boy = {
    name : "Mike",
    showName: function(){
        //console.log(boy.name);
					console.log(this.name);
    }
};

boy.showName();
Mike 가 출력 된다. 여기엔 문제가 좀 있다.

let man = boy; //man 과 boy 로 접근 가능하게 했다.
boy = null; // boy 는 null 이 되었다.
man.showName(); // 에러 발생!!
왜??????????
boy.name 인데 boy 는 null 이라서 에러가 나는 것이다.
this.name 으로 바꿔준다.

//this를 출력해보자.
let boy = {
    name : "Mike",
    showName: function(){
        console.log(this);
    }
};
boy 객체가 출력된다.

화살표 함수를 사용해보자.
let boy = {
    name : "Mike",
    showName: () => console.log(this)
};

window 가 출력된다.
화살표 함수로 메소드를 작성하면 boy를 가리크지 않고, window를 가르킨다.
객체 메소드를 작성할 때는 화살표 사용은 주의하자!