S1. JavaScript Koans

Haizel·2022년 11월 16일
0

Front-End Developer 되기

목록 보기
15/70
post-thumbnail

노션으로 보기

01. Expect

expect 사용법


  • **expect(테스트하는 값). 기대하는 조건**
    • expect(isEven(3)).to be.true

    • expect(1+2).to.equal(3)

      • .equal은 두 값의 타입까지 엄격하게 같은지 검사한다(Strict equality)
  • ‘기대하는 조건’에 해당하는 함수 ⇒ matcher이라고 한다.
    • ‘참인 것이어야 한다’ → to.be.true
    • ‘3과 같아야 한다’ → to.equal(3)
  • matcher는 mocha, chai framework 등 다양한 matcher이 있다.
🛠️ **isEven() 이란 ?**

02. Types-part1

비교연산자 ======


== (loose equality) : 두 값의 일치여부를 느슨하게 검사

  • ==는 실행 중 타입 변환이 일어나 → 타입이 같지 않더라도 일치한다고 본다.

**===** (strcit equality) : 두 값의 일치여부를 엄격하게 검사

  • 두 값의 타입까지 일치해야 한다.

String + number + Boolean ?



1 + '1' ; // '11' -> 숫자 + 문자 : 모두 문자로 취급

123 - '1' ; // 122 -> 문자 - 숫자 : 모두 숫자로 취급

1 + true ; //  2 -> 숫자 + boolean : true는 1, false는 0으로 숫자로 취급

'1' + true ; // '1true' -> 문자 + boolean : 모두 문자로 취급

03. const

1. const 로 선언된 변수엔 재할당(reassingment)이 금지된다.


const constNum = 0;
      constNum = 1; //불가

2. const 로 선언된 배열은 새로운 요소의 추가/삭제가 가능하다.


const arr = [];   //const로 선언된 배열
const number = 2;
arr.push(number);
arr[0] === 2  
arr = [2]        //새로운 요소의 추가,
arr.pop();       
arr =[];         //삭제가 가능하다.

3. const로 선언된 객체는 속성을 추가/삭제 할 수 있다.


const obj = {x :1}

delet.obj.x;
obj === {}

obj = {x : 123} //const로 선언했기 때문에 -> 재할당은 불가(추가/삭제만 가능)
🛠️ **왜 재할당도 안되는 `const` 키워드를 굳이 써야 할까?** 🛠️ [**구글 자바스크립트 코딩 스타일 가이드**](https://google.github.io/styleguide/jsguide.html#features-use-const-and-let)

04. Scope

1. Scope에서 함수 선언식(declaration)과 함수 표현식(Expression)의 차이


  • scope : 변수의 값(변수에 담긴 값)을 찾을 때 확인하는 곳
  • 함수 선언식과 함수표현식
// 함수선언문 
function foo() {
console.log('hello')' }

//함수표현식
var foo2 = function() {
console.log('hello2') }
 }
  • 함수선언식과 함수표현식의 스코프 차이
let funcExpressed = 'to be a function';
function funcDeclared() {return 'this is a function declaration'}; //함수선언식

typeof funcExpressed === 'string'
typeof funcDeclared === 'function'

//

const funcContainer = { func: funcExpressed }; //함수표현식
funcContainer.func() === 'this is a function expression'

funcContainer.func = funcDeclared; //funcDeclared() : 함수선언식
funcContainer.func() === 'this is a function declaration'
🛠️ **함수선언과 함수표현의 차이**
  • 변수 선언 : var let const
  • 함수 선언식 : function
  • 함수 표현식 : let cosnt
🛠️ **자바스크립트 함수 호이스팅(hoisting)이란?**
  • 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미
  • 즉, 변수의 선언과 초기화를 분리 → ‘선언’ 만 코드의 최상단에 옮기는 것
    • 따라서 변수 사용코드 > 변수 정의 코드보다 먼저 등장할 수 있다.
  1. 변수 호이스팅
  • **var 로 선언한 변수 :** 호이스팅 시 undefined 로 변수를 초기화 (호이스팅 발생)
//변수 호이스팅 : 변수 선언보다 호출이 먼저 됐을때 -> var
console.log(vari) //error가 아닌 undefined가 할당된다(초기화)
var vari = 'vari'
console.log(vari) //'vari'
  • **let const 로 선언한 변수, 함수표현식 :** 호이스팅 시 변수 초기화되지 않고 에러 발생

    →호이스팅이 일어나긴 하지만, TDZ(일시적 사각지대)에 머물게 되어 → 참조에러가 발생한다.

//변수 호이스팅 : 변수 선언보다 호출이 먼저 됐을때 -> let, const
console.log(vari) //error 발생
let(const) vari = 'vari'

변수 호이스팅의 결론

  • 호이스팅의 대상은 선언문 상단에서 참조, 할당이 가능하다.
  • 모든 변수 선언은 호이스팅이 발생한다.
  • 그러나 var키워드로 선언한 변수만 → 호이스팅이 발생하는 것처럼 보인다.
  1. 함수 호이스팅
  • **function** 함수선언문으로 정의한 함수 : 함수 호이스팅이 일어난다.
  • 함수 호이스팅은 함수 선언 이전에 호출된다.

참고자료

⇒ 하지만 호이스팅은 절대 좋은게 아니다 !!!

→ 왜나면 호출을 안했는데 호출이 되니까….

→ 따라서 <자바스크립트 학심 가이드>의 저자는 표현식을 권장한다….(JSON 만든 분)

2. Lexical scope(어휘적 스코프)


  • Lexical scope : 함수를 어디에 선언했는지에 따라 상위 스코프를 결정하는 것이다. (호출이 아니다)
function () {
    let message = 'Outer';

    function getMessage() {
      return message;
    }

    function shadowGlobal() {
      let message = 'Inner';
      return message;
    }

    function shadowGlobal2(message) {
      return message;
    }

    function shadowParameter(message) {
      message = 'Do not use parameters like this!';
      return message;
    }

//문제
getMessage(); // 'outer'
shadowGlobal(); // 'Inner'
shadowGlobal2('Parameter'); // 'Parameter'
shadowParameter('Parameter'); // 'Do not use parameters like this!'
message; // 'outer'

3. 클로저(Closure)


  • 클로저 : 함수와 함수가 선언된 어휘적 환경
    • 어휘적 환경 : 함수를 둘러싼 환경으로 기존에 선언되어 있던 환경을 말한다.(렉시컬 스코프)
    • 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성
  • 따라서 클로저는 내부함수가 외부함수의 지역변수에 접근할 수 있다.
function () {
    function increaseBy(increaseByAmount) {
      return function (numberToIncrease) {
        return numberToIncrease + increaseByAmount;
      };   }

    const increaseBy3 = increaseBy(3);
    const increaseBy5 = increaseBy(5);

//문제
increaseBy3(10); // increaseBy3(3)(10) = 13
increaseBy5(10); //increaseBy(5)(10) = 15
increaseBy(8)(6) + increaseBy(5)(9); // 14+14 = 28

참고자료

4. Lexical scope와 Closure(클로저)


❌ 사실 잘 모르겠다 ㅠㅠㅠㅠ

function () {              //외부 익명함수 안에 outerFn(),innerFn()내부 함수 존재
    let age = 27;
    let name = 'jin';
    let height = 179;

    function outerFn() {
      let age = 24;
      name = 'jimin';        //지역변수 -> 전역변수
      let height = 178;

      function innerFn() {
        age = 26;            //지역변수 -> 전역변수
        let name = 'suga';
        return height;

      }   //여기까지가 outerFn 함수'

      innerFn();
      
      //문제1)
      return age; // 26
      return name; //'Jimin' outerFn()가 인접함수 임으로 여기서 선언된 값 가져옴

      return innerFn;
    }
    const innerFn = outerFn();  // -> function innerFn()에 명시된 내용이 없어짐
     }); 
    });

//const innerFn = outerFn()됨에 따라 -> 함수가 아래와 같이 정리된다.

function () {              
    let age = 27;
    let name = 'jin';
    let height = 179;

    function outerFn() {
      let age = 24;
      name = 'jimin';        
      let height = 178;

  function innerFn() {
        age = 26;            //지역변수 -> 전역변수
        let name = 'suga';
        return height;

      } 

      innerFn()

    //문제2)
    age; // 27
    name; // 'Jimin'
    innerFn(); // 178
🛠️ **클로저란 ?**
  • JavaScript의 함수는 일급 객체 → 그냥 그대로 암기
  • JavaScript의 함수는 : 변수에 할당 가능, 리턴도 가능, 매개변수로도 넣을 수 있다 등등

클로저의 조건

  1. 함수가 → 함수를 리턴하는 형식이 나온다면 → 일단 클로저라고 의심!

  2. 그리고 리턴되고 있는 함수가 외부함수의 변수를 참조한다? → 이게 바로 클로저 !

클로저를 사용하는 이유

→ 변수를 안전하게 보호하기 위해(은닉)

→ 리턴된 함수를 사용하지 않으면 다른 요인으로 변수 못 바꾼다.

05. ArrowFunction(화살표 함수)

1. 화살표 함수 사용법


  1. function 키워드를 생략하고 화살표 => 를 붙인다.

  2. 리턴을 생략할 수 있다.

const subtract = (x, y) => x - y
  1. 파라미터가 하나일 경우 → 소괄호를 생략하고, 필요에 따라 소괄호를 붙일 수 있다.
const divideBy10 = x => x / 10     //소괄호 생략(파라미터 1개)
const multiply = (x, y) => (x * y) //소괄호 붙임(파라미터 2개)

2. 화살표 함수로 클로저 표현하기


  1. 함수표현식에 활용하기
const subtractor = x => y => {  //외부x함수 안에 x-y값을 리턴하는 내부y함수(클로저)
      return x - y }            //리턴은 생략가능하다.

subtractor(50)(10); // 40
  1. HTML에 활용하기
const htmlMaker = tag => textContent => `<${tag}>${textContent}</${tag}>
htmlMaker('div')('code states'); // '<div>code states</div>'

const liMaker = htmlMaker('li')
liMaker('1st item'); //'<li>1st item</li>'

06. Types-part2

1. 원시 자료형


  • 원시형 자료형 : **객체**가 아니면서 method 를 가지지 않는 6가지 데이터를 말한다.
    • string, number, bigint, boolean, undefined, symbol, (null)
  • ‘값’을 할당하며, immutable(불변, 정적)하다.
  • Stack : 원시자료형 데이터가 저장되는 공간

2. 원시 자료형은 immutable 하다.


  • 값 자체에 대한 변경이 불가능하다.
let name = 'codestates';

name; // 'codestates'
name.toUpperCase(); // 'CODESTATES'
name; // 'codestates' -> 값이 변경되지 않는다.
  • 하지만 새로운 값으로 재할당은 가능하다.
name = name.toUpperCase();

name; // 'CODESTATES'

3. 원시 자료형을 변수에 할당하면, 값 자체의 복사가 일어난다.


let overTwenty = true;
  let allowedToDrink = overTwenty; // allowedToDrink = true;

 overTwenty = false;
    overTwenty; //false
    allowedToDrink; //true -> allowedToDrink는 'overTwenty = true' 의 값 자체를 복사했기 때문에 재 할당해도 변하지 않는다.

let variable = 'variable';
    let variableCopy = 'variableCopy';
    variableCopy = variable;
    variable = variableCopy;
  
    variable; // 'variable'

4. 원시자료형 or 원시자료형의 데이터가 함수의 전달인자로 전달되면 → 값 자체가 복사된다.


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

    //문제1)
     currentYear; // 2020

    function afterTenYears2(currentYear) {
      currentYear = currentYear + 10;
      return currentYear; }
   
    let after10 = afterTenYears2(currentYear); 

    //문제2)
      currentYear; //2020
      after10; //2030

     });

5. 참조 자료형


  • 배열[] , 객체{} , 함수function() {}

  • ‘주소(refer)’를 할당하며, mutable(동적)이다.

  • Stack : 원시자료형 데이터가 저장되는 공간

    =================================

  • **heap : Object 자료형 데이터가 저장되는 공간**

6. 참조 자료형 데이터는 동적으로 변한다.


const obj = {};
    Object.keys(obj).length; //0이다

    obj['name'] = 'codestates';
    obj.quality = 'best';
    obj.product = ['sw engineering', 'product manager', 'growth marketing', 'data science'];

 Object.keys(obj).length; //3이 된다.

    delete obj.name;
    Object.keys(obj).length //그리고 2로 변한다.

7. 참조자료형을 변수로 할당할 경우 → 데이터의 주소가 저장된다.


  • 예제 1)
const overTwenty = ['hongsik', 'minchul', 'hoyong'];
   let allowedToDrink = overTwenty; //참조자료형을 변수로 할당할 경우-> 참조자료형의 주소
   overTwenty.push('san');          //가 저장된다.

  allowedToDrink; // ['hongsik', 'minchul', 'hoyong', 'san']

  overTwenty[1] = 'chanyoung';
  expect(allowedToDrink[1]).to.deep.equal('chanyoung');
  • 예제 2)
const ages = [22, 23, 27];
    allowedToDrink = ages; 
    expect(allowedToDrink === ages); //true
    expect(allowedToDrink === [22, 23, 27]); //false -> 주소가 다르다.
  • 예제 3)
const person = {
      son: {
        age: 9, }, };

const boy = person.son;
    boy.age = 20;  //person.son.age = 20
    expect(person.son.age); // 20
    expect(person.son === boy); // true -> 주소가 동일하다.
    expect(person.son === { age: 9 });  // false -> { age: 20 }이다.
    expect(person.son === { age: 20 });  // 답은 맞지만 두 값의 주소가 다르다!
🛠️ `**.equal` 과 `.deep.equal`의 차이점은 ?**

07. Array

1. Array의 기본기


const multiTypeArr = [
      0,
      1,
      'two',
      function () {
        return 3;
      },
      { value1: 4, value2: 5 },
      [6, 7],
    ];

multiTypeArr[4].value1; //4
multiTypeArr[4].value2; //5
multiTypeArr[5][0]; //6
multiTypeArr[5][1]; //7 

2. Array의 요소(element)를 다루는 방법


  • mutable Method : 원본 배열을 직접 변경함
    • **.pop() .push() .shift() .unshift() .splice()**
  • Immutable Method : 원본 배열을 변경하지 않고 새로운 배열을 반환한다
    • .**slice() .concat()**
arr = [1,2,3];
const poppedValue = arr.pop();   
    expect(poppedValue); // 3 -> arr.pop() 자체는 삭제된 요소 3이다
    expect(arr); // [1, 2]

//.pop()은 원본 배열을 직접 변경하는 mutable method이다.

3. Array 메소드의 Slice


  • .**slice() : immutable method**
  • **.slice( a )** : ****a부터 끝까지 추출
  • **.slice( a, b ) : a부터 b앞까지** 추출
const arr = ['peanut', 'butter', 'and', 'jelly'];

expect(arr.slice(1)) // ['butter', 'and', 'jelly']

1)추출 시작점 = 추출 종료점이거나
expect(arr.slice(2, 2) // []

2)추출종료점이 0이거나
expect(arr.slice(3, 0)) // []

3)추출시작점이 엘리먼트보다 큰 경우
expect(arr.slice(5, 1) // // []

=> 빈배열을 반환한다.

4)엘리먼트가 0일 경우 -> arr 전체를 복사한다.
expect(arr.slice(0) // ['peanut', 'butter', 'and', 'jelly'];

4. Array를 함수의 전달인자로 전달할 경우 → reference가 전달된다.


function () {

 const arr = ['zero', 'one', 'two', 'three', 'four', 'five'];

 function passedByReference(refArr) {
        refArr[1] = 'changed in function'}

 passedByReference(arr);
    expect(arr[1]).to.equal('changed in function');
  
// arr = ['zero', 'changed in function', 'two', 'three', 'four', 'five']

const assignedArr = arr;
    assignedArr[5] = 'changed in assignedArr';
    expect(arr[5]).to.equal('changed in assignedArr'); 

//arr = ['zero', 'changed in function', 'two', 'three', 'four', 'changed in assignedArr']

    const copiedArr = arr.slice();
 //slice에 인자가 없으면 arr 전체를 반환 + slice는 immutable method로 원본 배열을 변경하지 않고 새로운 배열을 반환함.

    copiedArr[3] = 'changed in copiedArr';
    expect(arr[3]).to.equal('three');  //slice는 원본 배열을 변경하지 않기 때문에     
                                         //=> 원본arr는 변경되지 않는다.

// arr =  ['zero', 'changed in function', 'two', 'three', 'four', 'changed in assignedArr']

08. Object

1. Object의 기본기


const emptyObj = {};
emptyObj.length // undefined -> *0이 아님*
const megalomaniac = {
      mastermind: 'Joker',
      henchwoman: 'Harley',
      getMembers: function () {
        return [this.mastermind, this.henchwoman];
      },
      relations: ['Anarky', 'Duela Dent', 'Lucy'],
      twins: {
        'Jared Leto': 'Suicide Squad',
        'Joaquin Phoenix': 'Joker',
        'Heath Ledger': 'The Dark Knight',
        'Jack Nicholson': 'Tim Burton Batman',
      },
    };

expect(megalomaniac.length).to.equal(undefined);
 //*왜 5가 아닌 undefined일까 ??? 찾아보기 !!
expect(megalomaniac.mastermind).to.equal('Joker');
expect(megalomaniac.henchwoman).to.equal('Harley'); //w가 소문자
expect(megalomaniac.henchWoman).to.equal(undefined); //w가 대문자 -> 선언된게 없다
expect(megalomaniac.getMembers()).to.deep.equal(['Joker', 'Harley']);
expect(megalomaniac.relations[2]).to.equal('Lucy');
expect(megalomaniac.twins['Heath Ledger']).to.deep.equal('The Dark Knight');
const megalomaniac = { mastermind: 'Agent Smith', henchman: 'Agent Smith' };

expect('mastermind' in megalomaniac); //true;
expect('secretary' in megalomaniac) // false;

2. this 는 method가 호출되는 시점에 결정된다.


const currentYear = new Date().getFullYear();
    const megalomaniac = {
      mastermind: 'James Wood',
      henchman: 'Adam West',
      birthYear: 1970,
      calculateAge: function (currentYear) {
        return currentYear - this.birthYear;
      },
      changeBirthYear: function (newYear) {
        this.birthYear = newYear;
      },
    };

일 때,

expect(currentYear).to.equal(new Date().getFullYear());
    expect(megalomaniac.calculateAge(currentYear)).to.equal(52); 
                                                   //2022 - 1970
    megalomaniac.birthYear = 2000;
    expect(megalomaniac.calculateAge(currentYear)).to.equal(22);
                                                  //2022 - 2000
    megalomaniac.changeBirthYear(2010);
    expect(megalomaniac.calculateAge(currentYear)).to.equal(12); 
                        //this.birthYear = 2010   => 2022 - 2010
🛠️ `**this` 란 ?**
  • this 의 값은 함수를 호출하는 방법에 의해 결정된다. 또 엄격모드와 비엄격모드에도 차이가 있다.
  • 하지만 화살표 함수는 자신의 this 가 없다. → 따라서 화살표 함수 바로 바깥범위의 this 를 찾는다
    • 화살표 함수에서의 this 는 자신을 감싼 정적 범위(lexical context)이다.

참고자료 : MDN 정의

🛠️ `**apply` , `call` ,`bind`란?** 🛠️ **일반 변수 조회 규칙이란 ?**

3. Object를 함수의 전달인자로 전달하면 reference가 전달된다.

→ 따라서 같은 주소를 공유하게 된다(원본 객체에 영향을 줌)


  1. 주어진 기본 객체 정보
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',
      },
    };
  1. object를 함수의 전달인자로 전달(얕은 복사)
function passedByReference(refObj) {
      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]);

//*함수의 전달인자로 object가 전달되어 값이 아닌 -> 주소가 전달되었다. 즉 같은 주소를 공유하게 된다(주소 복사)
//이때문에 함수를 통해 객체의 value 값을 바꿀 경우 -> 원본 value의 값도 변한다(같은 주소를 공유하고 있기 때문이다)
  1. .**assign을 통한 복사(주소가 아닌 새로운 객체로 복사)**

**object.assign(목표객체, 출처객체)**: 출처객체의 속성을 복사해 →목표객체에 반환한다.

const copiedObj = Object.assign({}, obj); //새로운 객체로 복사(별도의 주소를 갖게 됨)
    copiedObj.mastermind = 'James Wood';
    expect(obj.mastermind).to.equal('Joker');

    obj.henchwoman = 'Harley';
    expect(copiedObj.henchwoman).to.equal('Adam West');  //따라서 원본 객체의 변경은 새롭게 복사한 객체에 영향을 끼치지 않는다.
    delete obj.twins['Jared Leto'];
    expect('Jared Leto' in copiedObj.twins).to.equal(false); // *하지만 assign()은 딱 1depth까지만 깊은 복사가 된다.

.assign() 깊은복사의 한계


.assign() 을 통해 주소복사 가 아닌 → 새로운 객체로 복사가 가능하다.

하지만 .assign() 의 한계는 딱 1 depth 까지만 복사 = 즉, 중첩함수는 복사가 되지 않는다.

  delete obj.twins['Jared Leto'];
    expect('Jared Leto' in copiedObj.twins).to.equal(false);
  • 의 경우 twins key 는 중첩함수(level 2 depth)로 새로운 객체가 아닌 주소로 복사되었다.
  • 따라서 원본 객체의 삭제는 → 새로운 객체의 삭제로 이어져 false 값이 나온다.

그렇다면 완벽한 Deep Copy를 위한 방법은?


  • 재귀적으로 깊은 복사를 수행
  • Lodash의 cloneDeep 함수 사용J
  • JSON.parse()와 JSON.stringify()함수 사용

🛠 **앝은 복사(shallow copy)와 깊은 복사(deep copy)**

깊은복사 deep copy

  1. 객체에 중첩되어있는 객체까지 모두 복사
  2. 원시 값처럼 완전한 복사본을 만드는 것
  3. 원시값을 할당한 경우 깊은복사라 부르기도 함

얕은복사 shallow copy

  1. 한 단계 까지만 복사하는 것을 말한다.
  2. 객체에 중첩되어 있는 객체의 경우 참조 값을 복사한다.
  3. 객체를 할당한 변수를 다른 변수에 할당하는 것이라 부르기도 함.

09. SpreadSyntax (전개문법)

함수 호출 시 전달인자의 순서


//1)전달인자가 많이 주어졌다면,
function returnFirstArg(firstArg) {
      return firstArg;
    }
}
    expect(returnFirstArg('first', 'second', 'third')).to.equal('first'); 
//함수 주어진 파라미터만큼만 리턴한다.

arguments와 rest parameter를 통해 배열이 된 전달인자(args)의 차이


step1. arguments와 rest parameter를 통해 배열 만들기

//1)**rest parameter를 통해 함수의 전달인자를 배열로 만들어 준다.-> parameter는 배열이다.**
// ->rest Parameter는 spread syntax를 통해 간단하게 구현된다.
function getAllParamsByRestParameter(...args) {
      return args  }
 
**//2)** arguments객체를 통해 배열 만들기 **-> arguments객체는 유사배열객체이다** 
function getAllParamsByArgumentsObj() {
      return arguments; 
    }

const restParams = getAllParamsByRestParameter('first', 'second', 'third');
const argumentsObj = getAllParamsByArgumentsObj('first', 'second', 'third');

step2. 배열 메서드로 활용하기

expect(restParams).to.deep.equal(['first', 'second', 'third']); 
 expect(Object.keys(argumentsObj)).to.deep.equal(['0','1','2']); //유사배열
 expect(Object.values(argumentsObj)).to.deep.equal(['first', 'second', 'third']);

대표적인 배열의 메서드
Object.keys(obj):
객체의 키만 담은 배열을 반환한다.

**Object.values(obj)** : 객체의 값만 담은 배열을 반환한다.

**Object.entries(obj)** : 객체의 [키:값] 쌍을 담은 배열을 반환한다.

step3. 진짜배열과 유사배열이 된 전달인자(args)의 차이는?

expect(restParams === argumentsObj).to.deep.equal(false); //주소가 다르다
    expect(typeof restParams).to.deep.equal('object');
    expect(typeof argumentsObj).to.deep.equal('object');
    expect(Array.isArray(restParams)).to.deep.equal(true); //**parameter**로 만든 배열은 **진짜배열이다.**
    expect(Array.isArray(argumentsObj)).to.deep.equal(false) /**/argumen**t로 만든 배열은 **유사배열객체**이다.
  • 유사배열이란?
    **//1)직접 배열 리터럴로 선언**
    let array = [1,2,3]
    
    **//2)다른 방법으로 배열 만들기**
    let nods = document.querySelecorAll('div')
    let els = document.body.children;
    function arraylike (..arr) {
     return arr
    }
    
    //3)Array.isArray로 확인하기
    Array.isArray(array) ;//true
    Array.isArray(nods) ;//false
    Array.isArray(els) ;//false
    Array.isArray(arraylike) ;//false

    결론

    1. 직접 배열 리터럴로 선언한 배열만 → 배열
    2. []로 감싸져있기만 한 객체들 → 유사배열
    3. 유사배열은 → 배열의 메서드를 사용할 수 없다.
  • 유사배열에 배열메소드를 사용하고 싶다면? → **array.from** 을 활용하자
    • **Array.from()** : 유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)을 얕게 복사해 새로운 Array 객체를 만든다.

    • 방법 : 유사 배열 객체로부터 배열을 만들고 싶다면 → value만 복사해 만든다.

      const argsArr = Array.from(argumentsObj) //Array.from을 통해 유사배열객체를 새로운 배열 객체로 만들어준다.
       expect(Array.isArray(argsArr)).to.deep.equal(true); //그럼 새롭게 만든 배열은 배열type으로 취급된다.
       expect(argsArr).to.deep.equal(['first', 'second', 'third']);
      expect(argsArr === restParams).to.deep.equal(false); //Array.from을 통해 새로운 배열이 되었기 때문에 기존 주소와 일치하지 않는다.

10. Destructuring (구조 분해 할당)

구조 분해 할당


  • 구조분해할당 : 배열이나 객체의 속성을 해체 → 그 값을 개별 변수에 담은 Javascript의 표현식
//1)기본 변수 할당
 var foo = ["one", "two", "three"];

 var [red, yellow, green] = foo;
 console.log(red); // "one"
 console.log(yellow); // "two"
 console.log(green); // "three"
    
//2)선언에서 분리한 할당 : 변수의 선언이 분리되어도 구조 분해를 통해 값을 할당할 수 있다.
 var a, b;

 [a, b] = [1, 2];
 console.log(a); // 1
 console.log(b); // 2

//3. 기본값 : 변수에 기본값을 할당하면, 분해한 값이 undefined일 때 -> 그 값을 대신 사용한다.
 var a, b;

 [a=5, b=7] = [1];
 console.log(a); // 1
 console.log(b); // 7

💡 const [first, ...middle, last] = array -> 즉 rest 문법은 마지막 인수로만 올 수 있다.

profile
한입 크기로 베어먹는 개발지식 🍰

0개의 댓글