
Koans는 불교에서 유래된 단어로, 결론을 내리기 전에 이게 왜 맞는지 깊게 고민한다는 의미를 가지고 있습니다.
JavaScript Koans는 부트캠프에서 하게 된 자바스크립트를 전체적으로 공부하고 되돌아보며 문제를 푸는 시스템입니다.
부트캠프에서 처음 해보는건 아니였지만 아직 익숙하지 않은 환경이라 적응하는
데 시간이 꽤 걸렸다.
❖ 호이스팅:
    expect(typeof funcDeclared).to.equal('function');
    expect(typeof funcExpressed).to.equal('string');
    function funcDeclared() {
      return 'this is a function declaration';
    }
    funcExpressed = function () {
      return 'this is a function expression';
    };
함수 선언문으로 정의된 함수는 호이스팅이 일어난다.
함수 표현식으로 작성된 함수는 호이스팅이 일어나지 않는다.
함수 표현식을 사용할 것을 권장한다.
❖ 변수 호이스팅: JavaScirpt에서 모든 변수는 undefined실행하는 과저에서 재할당하는 방식으로 코드가 동작하는데 
console.log(vari);// undefined
var vari = 'vari'
console.log(variable)
let variable= 'variable' // cannot acces 'variable' 
호이스팅 일어나지 않도록하는게 좋음 변수 선언하기전에 console.log했을때 오류 나는게 좋음
  it('lexical scope에 대해서 확인합니다.', function () {
    let message = 'Outer';
    function getMessage() {
      //함수 내부에 message가 없으니 외부에서 참조
      return message;
    }
    function shadowGlobal() {
      let message = 'Inner';
      return message;
      //함수 내부에 message가 있으니 내부에서 참조
    }
    function shadowGlobal2(message) {
      return message;
      //함수 내부에 message 매개변수가 있기때문에 있다고봄(매개변수 참조)
    }
    function shadowParameter(message) {
      message = 'Do not use parameters like this!';
      return message;
      // 재할당, 외부 변수에 재할당, 파라미터 이런식으로 쓰지마라
    }
    expect(getMessage()).to.equal('Outer');
    expect(shadowGlobal()).to.equal('Inner');
    expect(shadowGlobal2('Parameter')).to.equal('Parameter');
    expect(shadowParameter('Parameter')).to.equal('Do not use parameters like this!');
    expect(message).to.equal('Outer');
  });
const increase = function(){
  let num = 0;
  return ++num;
클로저활용
const increase = function(){
  let num = 0;
  return function (){	//이 내부함수의 렉시컬환경은 함수가 선언된 장소(increas함수 전체) 외부에서 num이라는 변수 참조할 수 없음
    return ++num;
  };
}
const increase = function(){
  let num = 0;
  return{
    plus: function() {return ++num},
    minus: function() {return --num},
    current: function() {return num}
  }
}
const increase1 = increase(){
console.log(increase1.plus());//1
console.log(increase1.plus());//2
console.log(increase1.plus());//3
console.log(increase1.minus());//2
console.log(increase1.current());//2
const increae1 = increase();외부에서 외부함수의 실행결과를 변수에 할당하면 increse1이라는게 이 함수의 이름이 된거처럼 되고 이 걸 사용하면 내부에 있는 변수에 접근 가능하게된다.
클로저 조건
  it('클로저(closure)에 대해 확인합니다.', function () {
    function increaseBy(increaseByAmount) {
      return function (numberToIncrease) {
        return numberToIncrease + increaseByAmount;
      };
    }
    const increaseBy3 = increaseBy(3);
    const increaseBy5 = increaseBy(5);
    expect(increaseBy3(10)).to.equal(13);
    expect(increaseBy5(10)).to.equal(15);
    expect(increaseBy(8)(6) + increaseBy(5)(9)).to.equal(28);
increaseBy3 은 다음과 동일한 의미
function increaeBy3 (numberToincreae){
return numberToIncrease +3;
  it('lexical scope와 closure에 대해 다시 확인합니다.', function () {
    let age = 27; 
    let name = 'jin'; // 'jimin'
    let height = 179;
    function outerFn() {
      let age = 24; //26
      name = 'jimin'; //'jimin'재할당, 내부에는 name없으니 jin ->jimin
      let height = 178;
      function innerFn() {
        age = 26; // innerFn함수 내부에 age가 없음 27->26
        let name = 'suga'; //innerFn내부에서만 'suga'
        return height;
      }
      innerFn();
      expect(age).to.equal(26);
      expect(name).to.equal('jimin');
      return innerFn;
    }
    const innerFn = outerFn(); //변수 InnerFn은 OuterFn 내부에 있는 InnerFn함수와 동일하게 동작
    expect(age).to.equal(27);// outerFn밖에서 참조할때 
    expect(name).to.equal('jimin');
    expect(innerFn()).to.equal(178); // innerFn실행 height없기 때문에 외부의 height참조해서 178
  });
});
outerfn의 리턴값을 innerfn에 저장, innerfn의 리턴은 이 함 수 자체
  it('Object를 함수의 전달인자로 전달할 경우, reference가 전달됩니다.', function () {
    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',
      },
    };
    function passedByReference(refObj) {
      refObj.henchwoman = 'Adam West'; //refObj로 전달된 henchwoman을 'Adam West'로 변경
    }
    passedByReference(obj);
    expect(obj.henchwoman).to.equal('Adam West');
    const assignedObj = obj; //객체가 할당된 변수를 다른 변수에 할당했을때 -> 같은 주소를 참조한다.
    assignedObj['relations'] = [1, 2, 3];
    expect(obj['relations']).to.deep.equal([1,2,3]);	//같은주소  참조하고있으니 변경하면 원본도 변경(복사는 x)
    const copiedObj = Object.assign({}, obj); //배열로 치면  arr.slice()
    copiedObj.mastermind = 'James Wood';
    expect(obj.mastermind).to.equal('Joker'); //copied만 바뀜 
    obj.henchwoman = 'Harley';
    expect(copiedObj.henchwoman).to.equal("Adam West"); //원본만 바꾼거임
    delete obj.twins['Jared Leto'];
    expect('Jared Leto' in copiedObj.twins).to.equal(false); //같은 주소 참조해서 삭제된다
  });
});