diff --git a/01_Introduction.js b/01_Introduction.js
new file mode 100644
index 0000000..99947ee
--- /dev/null
+++ b/01_Introduction.js
@@ -0,0 +1,80 @@
+describe('expect에 대해서 학습합니다.', function () {
+ /*
+ 아래 코드는 여러분이 작성한 함수가 주어진 입력값에 대해서 리턴하는 값이 기대하는 값과 같은지를 비교하는 것입니다.
+
+ 이때 테스트하는 값과 기대값을 비교하기 위해 expect 함수를 사용합니다.
+ expect의 사용법은 아래와 같습니다.
+
+ expect(테스트하는값).기대하는조건
+ expect(isEven(3)).to.be.true => 'isEven(3)'의 결과값은 참(true)이어야 한다'
+ expect(1 + 2).to.equal(3) => 'sum(1, 2)의 결과값은 3과 같아야(equal) 한다'
+
+ '기대하는조건'에 해당하는 함수를 matcher라고 합니다.
+ '참인 것이어야 한다' => to.be.true
+ '3과 같아야 한다' => to.equal(3)
+
+ mocha, chai framework에는 다양한 matcher가 있지만, 이번 과제에서는 그 일부가 사용됩니다.
+ 궁금하시면 아래 링크를 통해 확인하시기 바랍니다. (어떤 것들이 있는지만 확인하는 수준이면 충분합니다.)
+ https://www.chaijs.com/api/bdd/
+
+ 여러분들은 expect를 활용하여 모든 Koans 과제를 완성하시면 됩니다.
+ 즉, 각 테스트 케이스가 테스트를 통과하도록 테스트 코드를 적절하게 변형하여야 합니다.
+ 단순히 테스트를 통과하는 것을 넘어, '왜 통과하는지'를 고민하는 시간이 되었으면 합니다.
+ */
+
+ it('테스트하는 값(expect의 전달인자)이 true인지의 여부를 검사합니다.', function () {
+ /*
+ 첫 문제는 가볍게 풀어봅시다.
+ expect 함수의 전달인자를 아래와 같이 false 대신 true로 변경하여 테스트를 통과하세요.
+ expect(true).to.be.true;
+ */
+ // TODO: 테스트가 통과될 수 있도록(테스트하는 값이 true가 되도록) expect의 첫 번째 전달인자를 수정합니다.
+ expect(true).to.be.true;
+ });
+
+ it('테스트하는 값(expect의 전달인자)이 falsy 여부를 검사합니다.', function () {
+ // 반대의 경우에는 어떻게 해야할까요?
+ // TODO: 테스트가 통과될 수 있도록(테스트하는 값이 false가 되도록) expect의 첫 번째 전달인자를 수정합니다.
+ expect(false).to.be.false;
+ });
+
+ /*
+ 2가지 matcher(.true, .false)를 통해 '기대하는 값'이 true인지 false인지 확인하는 방법을 학습했습니다.
+ 이 때, '기대하는 값'은 표현식(expression)이거나 함수의 실제 실행 결과입니다.
+ 1) 표현식: true || false, 1 + 1, 10 * 3
+ 2) 함수의 실행: isEven(3), sum(1, 2)
+
+ 보시면 알 수 있듯이, '기대하는 값'은 true, false 뿐만 아니라 어떤 구체적인 값인 경우가 있습니다.
+ 이 경우 '기대하는 값'이 '특정 값'과 같은지를 비교해서 테스트를 진행하면 됩니다.
+ 가장 간단한 방법은 비교 연산자 === 을 사용하는 방법이 있습니다.
+ '기대하는 값과 특정 값을 비교한 결과'가 true인지 확인하면 됩니다.
+ expect('기대하는 값과 특정 값을 비교한 결과').to.be.true;
+ */
+ it("'테스트하는 값'을 '기대하는 값'과 비교한 결과가 참 인지 확인합니다.", function () {
+ // '테스트하는 값'은 우리가 작성한 어떤 코드의 실제 실행 결과 값이므로 '실제 값'이라고 불러도 됩니다.
+ let actualValue = 1 + 1;
+ let expectedValue = 2; // TODO: 'FILL_ME_IN'을 변경하여 테스트 케이스를 완성합니다.
+ expect(actualValue === expectedValue).to.be.true;
+ });
+
+ /*
+ 이처럼 to.be.true, to.be.false 만을 가지고도 많은 테스트 케이스를 작성할 수 있습니다.
+ 하지만 이는 직관적이지 않고 다소 불편합니다.
+ 두 값 A와 B를 '비교한 결과'가 참인지를 확인하는 대신에 직접 A가 B와 같은지 확인하는 matcher가 없을까요?
+ .equal이 바로 그런 역할을 합니다. 아래 테스트 코드는 '테스트하는값'이 '기대하는값'과 같은지 직접 확인합니다.
+ expect('테스트하는값').to.equal('기대하는값');
+
+ 이제 'FILL_ME_IN'을 적절한 값으로 변경하여 테스트 케이스를 완성하시면 됩니다.
+ 이후에도 같은 방식으로 'FILL_ME_IN' 변경하면 됩니다.
+ */
+ it('Matcher .equal 의 사용법을 학습합니다.', function () {
+ let expectedValue = 2; // TODO
+ // .equal은 두 값이 타입까지 엄격하게 같은지 검사(strict equality, ===)합니다.
+ expect(1 + 1).to.equal(expectedValue);
+ });
+
+ it('Matcher .equal의 사용법을 학습합니다.', function () {
+ let actualValue = (1 + 1).toString();
+ expect(actualValue).to.equal("2"); // TODO
+ });
+});
diff --git a/02_Types-part1.js b/02_Types-part1.js
new file mode 100644
index 0000000..b3157e8
--- /dev/null
+++ b/02_Types-part1.js
@@ -0,0 +1,67 @@
+describe('type에 대해서 학습합니다.', function () {
+ it("비교연산자 '=='는 두 값의 일치 여부를 느슨하게 검사(loose equality)합니다.", function () {
+ let actualValue = 1 + 1;
+ let expectedValue = 2;
+ expect(actualValue == expectedValue).to.be.true;
+
+ /*
+ 혹시 'FILL_ME_IN'을 '2'(문자열 '2')로 변경해도 테스트가 통과된다는 사실을 알고 계십니까?
+ '=='의 실행 중 타입 변환(type coercion)이 일어나기 때문입니다.
+ 이는 다소 복잡하고, 명확한 규칙이 존재하지 않습니다.
+ 느슨한 동치 연산자 '=='의 느슨함을 보여주는 예시가 아래에 있습니다.
+ 아래 테스트 코드들의 주석을 제거해도 이 테스트는 통과합니다.
+ */
+
+ // expect(0 == false).to.be.true;
+ // expect('' == false).to.be.true;
+ // expect([] == false).to.be.true;
+ // expect(![] == false).to.be.true;
+ // expect([] == ![]).to.be.true;
+ // expect([] == '').to.be.true;
+ // expect([] == 0).to.be.true;
+ // expect([''] == '').to.be.true;
+ // expect([''] == 0).to.be.true;
+ // expect([0] == 0).to.be.true;
+ });
+
+ /*
+ 사실 느슨한 동치 연산(loose equality)는 프로그램의 작동을 예측하기 다소 어렵게 만듭니다.
+ '=='의 특성을 정확하게 외워서 모든 상황에 대응하겠다는 자세는 접어두시기 바랍니다.
+ 매우 비효율적일뿐더러 일반적인 컴퓨터 프로그래밍 언어의 관습(convention)과도 거리가 먼 자세입니다.
+ 지금부터는 엄격한 동치 연산(strict equality) '==='을 사용하시기 바랍니다.
+ */
+
+ it("비교연산자 '==='는 두 값의 일치 여부를 엄격하게 검사(strict equality)합니다.", function () {
+ let actualValue = 1 + 1;
+ let expectedValue = 2;
+ expect(actualValue === expectedValue).to.be.true;
+ // 이제 'FILL_ME_IN'을 대신할 수 있는 건 number 타입의 2뿐입니다.
+ // 문자열 '2'는 테스트를 통과하지 못합니다.
+ });
+
+ it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
+ expect(1 + '1').to.equal("11");
+ });
+
+ it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
+ expect(123 - '1').to.equal(122);
+ });
+
+ it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
+ expect(1 + true).to.equal(2);
+ });
+
+ it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
+ expect('1' + true).to.equal("1true");
+ });
+
+ /*
+ 지금까지 본 것처럼 자바스크립트에는 다소 이해하기 힘든 부분들이 존재합니다.
+ 아래처럼 자바스크립트의 별난(quirky) 부분들을 따로 모아둔 저장소도 있을 정도입니다.
+ https://github.com/denysdovhan/wtfjs
+
+ 여기서도 동치 연산을 학습하면서 당부한 자세가 요구됩니다.
+ 이런 별난 특성들을 전부 외워서 모든 상황에 대응하려고 하지 말고, 올바른 코딩 습관을 기르시기 바랍니다.
+ 대표적으로 최대한 같은 타입끼리 연산을 하고, 즉 엄격한 동치 연산('===')을 사용하고, 조건문에 비교 연산을 명시하는 것이 훨씬 좋습니다.
+ */
+});
diff --git a/03_LetConst.js b/03_LetConst.js
new file mode 100644
index 0000000..0ae67e7
--- /dev/null
+++ b/03_LetConst.js
@@ -0,0 +1,44 @@
+describe("'const'에 대해서 학습합니다.", function () {
+ it("'const'로 선언된 변수에는 재할당(reassignment)이 금지됩니다.", function () {
+ // 아래 코드에서 문제가 되는 부분을 삭제합니다.
+ const constNum = 0;
+ expect(constNum).to.equal(0);
+
+ const constString = 'I am a const';
+ expect(constString).to.equal('I am a const');
+ });
+
+ it("'const'로 선언된 배열의 경우 새로운 요소를 추가하거나 삭제할 수 있습니다.", function () {
+ const arr = [];
+ const toBePushed = 42;
+ arr.push(toBePushed);
+ expect(arr[0]).to.equal(42);
+
+ // 여전히 재할당은 금지됩니다.
+ // arr = [1, 2, 3];
+ });
+
+ it("'const'로 선언된 객체의 경우, 속성을 추가하거나 삭제할 수 있습니다.", function () {
+ const obj = { x: 1 };
+ expect(obj.x).to.equal(1);
+
+ delete obj.x;
+ expect(obj.x).to.equal(undefined);
+
+ // 여전히 재할당은 금지됩니다.
+ // obj = { x: 123 };
+
+ obj.occupation = 'SW Engineer';
+ expect(obj['occupation']).to.equal('SW Engineer');
+ });
+
+ /*
+ 재할당도 안되는 'const' 키워드를 굳이 써야하는지 이해가 안 될수도 있습니다.
+ 'let' 키워드는 재할당이 가능하기 때문에 여러모로 편하고, 큰 문제도 없어 보이기 때문입니다.
+ 이에 대해서 잠시 고민하신 후, 'const'가 추천되는 이유에 대해 직접 찾아보시기 바랍니다.
+
+ 동기 부여를 위해 구글 자바스크립트 코딩 스타일 가이드를 소개해 드립니다.
+ 세계의 탑코더들이 있는 구글 스타일 가이드는 선언 키워드에 대해서 어떻게 안내하고 있을까요?
+ https://google.github.io/styleguide/jsguide.html#features-use-const-and-let
+ */
+});
diff --git a/04_Scope.js b/04_Scope.js
new file mode 100644
index 0000000..875ffb5
--- /dev/null
+++ b/04_Scope.js
@@ -0,0 +1,140 @@
+describe('scope 대해서 학습합니다.', function () {
+ // scope는 변수의 값(변수에 담긴 값)을 찾을 때 확인하는 곳을 말합니다. 반드시 기억하시기 바랍니다.
+ it('함수 선언식(declaration)과 함수 표현식(expression)의 차이를 확인합니다.', function () {
+ let funcExpressed = 'to be a function';
+
+ 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';
+ };
+
+ // 자바스크립트 함수 호이스팅(hoisting)에 대해서 검색해 봅니다.
+
+ const funcContainer = { func: funcExpressed };
+ expect(funcContainer.func()).to.equal('this is a function expression');
+
+ funcContainer.func = funcDeclared;
+ expect(funcContainer.func()).to.equal('this is a function declaration');
+ });
+
+ it('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;
+ }
+
+ 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');
+ });
+
+ it('default parameter에 대해 확인합니다.', function () {
+ function defaultParameter(num = 5) {
+ // num=5 초기값 설정
+ return num;
+ }
+
+ expect(defaultParameter()).to.equal(5);
+ expect(defaultParameter(10)).to.equal(10);
+
+ function pushNum(num, arr = []) {
+ arr.push(num);
+ return arr;
+ }
+
+ expect(pushNum(10)).to.deep.equal([10]);
+ expect(pushNum(20)).to.deep.equal([20]);
+ expect(pushNum(4, [1, 2, 3])).to.deep.equal([1, 2, 3, 4]);
+
+
+ });
+
+ it('클로저(closure)에 대해 확인합니다.', function () {
+ function increaseBy(increaseByAmount) {
+ return function (numberToIncrease) {
+ return numberToIncrease + increaseByAmount;
+ // increaseByAmount => 3
+ };
+ }
+
+ 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);
+
+ /*
+ mdn에 따르면 클로저의 정의는 다음과 같습니다. 반드시 기억하시기 바랍니다.
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
+
+ A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.
+
+ 클로저는 함수와 함수가 선언된 어휘적 환경의 조합을 말한다.
+ 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.
+
+ 여기서의 키워드는 "함수가 선언"된 "어휘적(lexical) 환경"입니다.
+ 특이하게도 자바스크립트는 함수가 호출되는 환경와 별개로, 기존에 선언되어 있던 환경 - 어휘적 환경 - 을 기준으로 변수를 조회하려고 합니다.
+ 유어클레스 영상에서 언급되는 "외부함수의 변수에 접근할 수 있는 내부함수"를 클로져 함수로 부르는 이유도 그렇습니다.
+
+ 클로저는 내부(inner) 함수가 외부(outer) 함수의 지역 변수에 접근할 수 있습니다.
+ 이를 유념하시고 클로저의 유즈 케이스를 검색해 보시기 바랍니다. 아래 검색 키워드를 활용합니다.
+ function factories
+ namespacing private variables/functions
+ */
+ });
+
+ it('lexical scope와 closure에 대해 다시 확인합니다.', 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();
+
+ expect(age).to.equal(26);
+ expect(name).to.equal('jimin');
+
+ return innerFn;
+ }
+
+ const innerFn = outerFn();
+
+ expect(age).to.equal(27);
+ expect(name).to.equal('jimin');
+ expect(innerFn()).to.equal(178);
+ });
+});
diff --git a/05_ArrowFunction.js b/05_ArrowFunction.js
new file mode 100644
index 0000000..32afdce
--- /dev/null
+++ b/05_ArrowFunction.js
@@ -0,0 +1,52 @@
+describe('화살표 함수에 관해서', function () {
+ it('함수 표현식 사용법을 복습합니다', function () {
+ const add = function (x, y) {
+ return x + y
+ }
+
+ expect(add(5, 8)).to.eql(13)
+ })
+
+ it('화살표 함수 사용법을 익힙니다', function () {
+ // function 키워드를 생략하고 화살표 => 를 붙입니다
+ const add = (x, y) => {
+ return x + y
+ }
+ expect(add(10, 20)).to.eql(30)
+
+ // 리턴을 생략할 수 있습니다
+ const subtract = (x, y) => x - y
+ expect(subtract(10, 20)).to.eql(-10)
+
+ // 필요에 따라 소괄호를 붙일 수도 있습니다
+ const multiply = (x, y) => (x * y)
+ expect(multiply(10, 20)).to.eql(200)
+
+ // 파라미터가 하나일 경우 소괄호 생략이 가능합니다
+ const divideBy10 = x => x / 10
+ expect(divideBy10(100)).to.eql(10)
+ })
+
+ it('화살표 함수를 이용해 클로저를 표현합니다', function () {
+ const adder = x => {
+ return y => {
+ return x + y
+ }
+ }
+
+ expect(adder(50)(10)).to.eql(60)
+
+ const subtractor = x => y => {
+ return x - y
+ }
+
+ expect(subtractor(50)(10)).to.eql(40)
+
+ const htmlMaker = tag => textContent => `<${tag}>${textContent}${tag}>`
+ expect(htmlMaker('div')('javascript')).to.eql('
javascript
')
+
+ const liMaker = htmlMaker('li') //-> undefined
+ expect(liMaker('1st item')).to.eql('1st item')
+ expect(liMaker('2nd item')).to.eql('2nd item')
+ })
+})
diff --git a/06_Types-part2.js b/06_Types-part2.js
new file mode 100644
index 0000000..7387caf
--- /dev/null
+++ b/06_Types-part2.js
@@ -0,0 +1,203 @@
+describe('primitive data type과 reference data type에 대해서 학습합니다.', function () {
+ /*
+
+ * 아래 주석이 이해하기 어렵다면, 유어클래스 Lesson - Primitive & Reference를 복습하세요 :)
+
+ 자바스크립트에서 원시 자료형(primitive data type 또는 원시값)은 객체가 아니면서 method를 가지지 않는 아래 6가지의 데이터를 말합니다.
+ string, number, bigint, boolean, undefined, symbol, (null)
+ */
+ it('원시 자료형은 값 자체에 대한 변경이 불가능(immutable)합니다.', function () {
+ let name = 'javascript';
+ expect(name).to.equal('javascript');
+ // 원본은 안바꿈 -> 대문자로 바꾸려면 nmae = nmae.toUppercase
+ expect(name.toUpperCase()).to.equal('JAVASCRIPT');
+ expect(name).to.equal('javascript');
+ // 새로운 값으로 재할당은 가능합니다.
+ name = name.toUpperCase();
+ expect(name).to.equal('JAVASCRIPT');
+
+ /*
+ 원시 자료형은 값 자체에 대한 변경이 불가능하다고 하는데, 한 변수에 다른 값을 할당하는 것은 변경이 된 것이 아닌가요?
+ let num1 = 123;
+ num2 = 123456;
+ 원시 자료형 그 자체('hello', 123, 456n, true 등)와 원시 자료형이 할당된 변수는 구분되어야 합니다.
+ 사과 박스에 귤을 담았다고 해서, 귤이 갑자기 사과가 되지는 않는 것과 같이 123이 갑자기 123456이 되지 않습니다.
+ */
+ });
+
+ it('원시 자료형을 변수에 할당할 경우, 값 자체의 복사가 일어납니다.', function () {
+ let overTwenty = true;
+ let allowedToDrink = overTwenty;
+
+ overTwenty = false;
+ expect(overTwenty).to.equal(false);
+ expect(allowedToDrink).to.equal(true);
+
+ let variable = 'variable';
+ let variableCopy = 'variableCopy';
+ variableCopy = variable; // -> variable = 'variable' / variableCopy = 'variable'
+ variable = variableCopy;
+ expect(variable).to.equal('variable');
+ });
+
+ it('원시 자료형 또는 원시 자료형의 데이터를 함수의 전달인자로 전달할 경우, 값 자체의 복사가 일어납니다.', function () {
+ let currentYear = 2020;
+ function afterTenYears(year) {
+ year = year + 10;
+ }
+ afterTenYears(currentYear);
+ expect(currentYear).to.equal(2020);
+ function afterTenYears2(currentYear) {
+ currentYear = currentYear + 10;
+ return currentYear;
+ }
+ let after10 = afterTenYears2(currentYear);
+ expect(currentYear).to.equal(2020);
+ expect(after10).to.equal(2030);
+ // 사실 함수의 전달인자도 변수에 자료(data)를 할당하는 것입니다.
+ // 함수를 호출하면서 넘긴 전달인자가 호출된 함수의 지역변수로 (매 호출 시마다) 새롭게 선언됩니다.
+ });
+
+ /*
+ 자바스크립트에서 원시 자료형이 아닌 모든 것은 참조 자료형 입니다. 배열([])과 객체({}), 함수(function(){})가 대표적입니다.
+
+ const pi = 3.14
+ const arr = ["hello", "world", "java", "spring"];
+
+ 위 두 가지 코드에서 어떤 차이를 찾으실 수 있나요? 아쉽게도 보기에는 큰 차이가 없습니다.
+ 하지만 자바스크립트는 보기와는 다르게 작동되는 부분이 있습니다. (under the hood)
+ 여기서 변수 pi에는 3.14라는 원시 자료형 '값'이 할당되고, arr에는 참조 자료형의 '주소'가 할당됩니다.
+ 영어 단어 reference 의미와 연결시켜보면 실제 데이터가 저장된 주소를 가리킨다(refer), 즉, 참조(reference)한다로 이해하면 쉽습니다.
+
+ 왜 참조 자료형에서는 '주소'를 할당할 수 밖에 없을까요?
+ 원시 자료형은 immutable 하다고 말씀 드렸습니다. 참조 자료형은, 그렇지 않습니다.
+
+ 우리가 배열에 요소를 추가 및 삭제하고, 객체에 속성을 추가 및 삭제할 수 있었습니다.
+ 이것 자체가, 참조 자료형은 이미 immutable하지 않다는 것을 보여주고 있습니다.
+ 언제든 데이터가 늘어나고 줄어들 수 있죠 (동적으로 변한다.), 그렇기 때문에 특별한 저장공간의 주소를 변수에 할당함으로써 더 잘 관리하고자 합니다.
+ 이런 저장 공간을 heap이라고 부릅니다.
+
+ 아래와 같이 코드가 작성되어 있다면...
+ let num = 123;
+ const msg = "hello";
+ let arr = [1, 2, 3];
+ const isOdd = true;
+
+ 원시 자료형의 데이터가 저장되는 공간 (stack)
+ 1 | num | 123
+ 2 | msg | "hello"
+ 3 | arr | heap의 12번부터 3개 // (실제 데이터가 저장되어 있는 주소)
+ 4 |isOdd| true
+ =====================================
+ Object 자료형의 데이터가 저장되는 공간 (heap)
+ 10 ||
+ 11 ||
+ 12 || 1
+ 13 || 2
+ 14 || 3
+ 실제 자바스크립트는 변수를 위와 같이 저장할 것입니다.
+
+ *
+ * 위의 원리가 잘 이해 되셨나요? heap과 stack이라는 용어가 어색하더라도, 위 원리가 잘 이해되었다면 괜찮습니다.
+ * 이해가 잘 안되시면, 원시 자료형이 할당되는 경우는 값 자체가 할당되고, 참조 자료형은 주소가 할당된다고 암기하셔도 좋습니다.
+ *
+ * const hello = "world"; // "world" 그 자체
+ * const arr = [1, 2, 3]; // [1, 2, 3] 의 메모리 주소 xxxxxx
+ *
+ */
+ it('참조 자료형의 데이터는 동적(dynamic)으로 변합니다.', function () {
+ const arr = [1, 2, 3];
+ expect(arr.length).to.equal(3);
+ arr.push(4, 5, 6);
+ expect(arr.length).to.equal(6);
+ arr.pop();
+ expect(arr.length).to.equal(5);
+
+ const obj = {};
+ expect(Object.keys(obj).length).to.equal(0);
+ obj['name'] = 'codestates';
+ obj.quality = 'best';
+ obj.product = ['sw engineering', 'product manager', 'growth marketing', 'data science'];
+ expect(Object.keys(obj).length).to.equal(3);
+ delete obj.name;
+ expect(Object.keys(obj).length).to.equal(2);
+ });
+
+ it('참조 자료형을 변수에 할당할 경우, 데이터의 주소가 저장됩니다.', function () {
+ /*
+ 참조 자료형의 경우, 값 자체의 복사가 일어나지 않는 이유는 어느 정도 납득할만한 이유가 있습니다.
+ 배열이 얼마나 많은 데이터를 가지고 있는지가 프로그램의 실행 중 수시로 변경될 수 있기 때문입니다.
+ 쉽게 생각해서 number 타입 데이터 100만개를 요소로 갖는 배열을 생각해 봅시다.
+ 따로 명시하지 않는 이상 100만개의 데이터를 일일히 복사하는 것은 상당히 비효율적입니다.
+ 따라서 일단은 주소만 복사해서 동일한 데이터를 바라보는 게 만드는 것이 효율적입니다.
+ 배열과 객체의 데이터를 복사하는 방법은 06_Array.js, 07_Object.js에서 다룹니다.
+ */
+ const overTwenty = ['hongsik', 'minchul', 'hoyong'];
+ let allowedToDrink = overTwenty;
+
+ overTwenty.push('san');
+ expect(allowedToDrink).to.deep.equal(['hongsik', 'minchul', 'hoyong', 'san']);
+ overTwenty[1] = 'chanyoung';
+ expect(allowedToDrink[1]).to.deep.equal('chanyoung');
+ // .deep.equal은 배열의 요소나 객체의 속성이 서로 같은지 확인하는 matcher입니다.
+ // .equal아닌 .deep.equal을 사용하는 이유는 아래 테스트 코드를 통해 고민하시기 바랍니다.
+
+ const ages = [22, 23, 27];
+ allowedToDrink = ages;
+ expect(allowedToDrink === ages).to.equal(true);
+
+ const nums1 = [1, 2, 3];
+ const nums2 = [1, 2, 3];
+ expect(nums1 === nums2).to.equal(false);
+
+ const person = {
+ son: {
+ age: 9,
+ },
+ };
+
+ const boy = person.son; //boy -> {age : 9};
+ boy.age = 20;
+ expect(person.son.age).to.equal(20);
+ expect(person.son === boy).to.equal(true);
+
+ /*
+ 아래의 테스트 코드들은 선뜻 받아들이기 힘들 수 있습니다.
+ const nums1 = [1, 2, 3];
+ const nums2 = [1, 2, 3];
+ expect(nums1 === nums2).to.equal(FILL_ME_IN);
+ 배열 nums1과 배열 num2에는 동일한 데이터 [1, 2, 3]이 들어있는 게 분명해 보이는데, 이 둘은 같지가 않습니다.
+ 사실 변수 num1와 num2는 배열이 아닙니다.
+ 참조 타입의 변수에는 (데이터에 대한) 주소만이 저장된다는 것을 떠올려 봅시다.
+
+ 정확히 말해서 변수 num1은 데이터 [1, 2, 3]이 저장되어 있는 메모리 공간(heap)을 가리키는 주소를 담고 있습니다.
+ 따라서 위의 코드는 각각 다음의 의미를 가지고 있습니다.
+ const nums1 = [1, 2, 3]; // [1, 2, 3]이 heap에 저장되고, 이 위치의 주소가 변수 num1에 저장된다.
+ const nums2 = [1, 2, 3]; // [1, 2, 3]이 heap에 저장되고, 이 위치의 주소가 변수 num2에 저장된다.
+ 이제 heap에는 두 개의 [1, 2, 3]이 저장되어 있고, 각각에 대한 주소가 변수 num1, num2에 저장되어 있습니다.
+ 이게 비효율적으로 보일수도 있습니다. 굳이 같은 데이터를 왜 한번 더 저장하는 지 이해하기란 쉽지 않습니다.
+
+ 하지만 [1, 2, 3]이 아니라 상당히 큰 데이터(예. length가 100,000인 배열)를 가지고 다시 생각해 봅시다.
+ const nums1 = [10, 2, 71, ..., 987]; // 길이 100,000개인 배열
+ const nums2 = [10, 2, 71, ..., 987]; // 길이 100,000개인 배열
+ 이 두 배열이 서로 같아서 두 번 저장할 필요가 없다고 말하려면, 일단 두 배열이 같은지 확인해야 합니다.
+ 이런 작업을 Object 자료형을 쓸 때마다 한다고 가정해보면, 이것이 얼마나 비효율적인지를 금방 알 수 있습니다.
+
+ 이제 아래와 같이 정리할 수 있습니다. 반드시 기억하시기 바랍니다.
+ Object 자료형은 데이터는 heap에 저장되고, 변수에 할당을 할 경우 변수에는 주소가 저장된다.
+ 1) [1, 2, 3]; // [1, 2, 3]이라는 데이터가 heap에 저장되지만 변수 할당이 되지 않아 주소는 어디에도 저장되지 않는다.
+ 2) const num1 = [1, 2, 3]; // // [1, 2, 3]이라는 데이터가 heap에 저장되고, 그 주소가 변수 num1에 저장된다.
+ 3) const num2 = [1, 2, 3]; // // [1, 2, 3]이라는 데이터가 heap에 저장되고, 그 주소가 변수 num2에 저장된다.
+ 1), 2), 3)에서 말하는 주소는 전부 다른 주소입니다.
+
+ 아래의 객체 간 비교도 동일한 논리로 이해하시면 됩니다.
+ expect(person.son === { age: 20 }).to.equal(FILL_ME_IN);
+
+ 다음 문제를 해결해 보시기 바랍니다.
+ const num1 = [1, 2, 3]; // [1, 2, 3]이 heap에 저장되고, 그 주소가 변수 num1에 저장된다.
+ const num2 = num1; // 변수 num1에 저장된 주소가 변수 num2에 저장된다.
+ // 두 변수 num1, num2는 같은 주소를 저장하고 있습니다. 아래 결과는 어떻게 될까요?
+ expect(num1 === num2).to.equal(FILL_ME_IN);
+ */
+ });
+});
diff --git a/07_Array.js b/07_Array.js
new file mode 100644
index 0000000..67d4996
--- /dev/null
+++ b/07_Array.js
@@ -0,0 +1,94 @@
+describe('Array에 대해서 학습합니다.', function () {
+ it('Array의 기본을 확인합니다.', function () {
+ const emptyArr = [];
+ expect(typeof emptyArr === 'array').to.equal(false);
+ expect(emptyArr.length).to.equal(0);
+
+ const multiTypeArr = [
+ 0,
+ 1,
+ 'two',
+ function () {
+ return 3;
+ },
+ { value1: 4, value2: 5 },
+ [6, 7],
+ ];
+ expect(multiTypeArr.length).to.equal(6);
+ expect(multiTypeArr[0]).to.equal(0);
+ expect(multiTypeArr[2]).to.equal('two');
+ expect(multiTypeArr[3]()).to.equal(3);
+ expect(multiTypeArr[4].value1).to.equal(4);
+ expect(multiTypeArr[4]['value2']).to.equal(5);
+ expect(multiTypeArr[5][1]).to.equal(7);
+ });
+
+ it('Array의 요소(element)를 다루는 방법을 확인합니다.', function () {
+ const arr = [];
+ expect(arr).to.deep.equal([]);
+
+ arr[0] = 1;
+ expect(arr).to.deep.equal([1]);
+
+ arr[1] = 2;
+ expect(arr).to.deep.equal([1, 2]);
+
+ arr.push(3);
+ expect(arr).to.deep.equal([1, 2, 3]);
+
+ const poppedValue = arr.pop(); // 3, arr = [1, 2]
+ // const poppedValue = arr.pop(); -> arr.pop(3) -> 뺀 값 Return
+ expect(poppedValue).to.equal(3);
+ expect(arr).to.deep.equal([1, 2]);
+ });
+
+ it('Array 메소드 slice를 확인합니다.', function () {
+ const arr = ['peanut', 'butter', 'and', 'jelly'];
+
+ expect(arr.slice(1)).to.deep.equal(['butter', 'and', 'jelly']);
+ expect(arr.slice(0, 1)).to.deep.equal(["peanut"]);
+ expect(arr.slice(0, 2)).to.deep.equal(['peanut', 'butter']);
+ expect(arr.slice(2, 2)).to.deep.equal([]);
+ expect(arr.slice(2, 20)).to.deep.equal(['and', 'jelly']);
+ expect(arr.slice(3, 0)).to.deep.equal([]);
+ expect(arr.slice(3, 100)).to.deep.equal(['jelly']);
+ expect(arr.slice(5, 1)).to.deep.equal([]);
+
+ // arr.slice는 arr의 값을 복사하여 새로운 배열을 리턴합니다.
+ // 아래의 코드는 arr 전체를 복사합니다. 자주 사용되니 기억하시기 바랍니다.
+ expect(arr.slice(0)).to.deep.equal(['peanut', 'butter', 'and', 'jelly']);
+ });
+
+ it('Array를 함수의 전달인자로 전달할 경우, reference가 전달됩니다.', function () {
+ // call(pass) by value와 call(pass) by reference의 차이에 대해서 학습합니다.
+ const arr = ['zero', 'one', 'two', 'three', 'four', 'five'];
+
+ function passedByReference(refArr) {
+ refArr[1] = 'changed in function';
+ }
+ passedByReference(arr);
+ // 깊은 복사
+ // 1. passedByReference(arr).slice(0);
+ // 2. passedByReference(...arr);
+ expect(arr[1]).to.equal('changed in function');
+
+ const assignedArr = arr;
+ assignedArr[5] = 'changed in assignedArr';
+ expect(arr[5]).to.equal('changed in assignedArr');
+
+ const copiedArr = arr.slice();
+ copiedArr[3] = 'changed in copiedArr';
+ expect(arr[3]).to.equal('three');
+ });
+
+ it('Array 메소드 shift와 unshift를 확인합니다.', function () {
+ const arr = [1, 2];
+
+ arr.unshift(3);
+ expect(arr).to.deep.equal([3, 1, 2]);
+
+ const shiftedValue = arr.shift();
+ expect(shiftedValue).to.deep.equal(3);
+ expect(arr).to.deep.equal([1, 2]);
+ });
+});
diff --git a/08_Object.js b/08_Object.js
new file mode 100644
index 0000000..077d893
--- /dev/null
+++ b/08_Object.js
@@ -0,0 +1,156 @@
+describe('Object에 대해서 학습합니다.', function () {
+ /*
+ 이번 과제에서는 객체의 기본적인 내용을 재확인합니다.
+ 이머시브 과정에서 객체를 보다 자세하게 학습하게 됩니다. (예. prototype)
+ */
+ it('Object의 기본을 확인합니다.', function () {
+ const emptyObj = {};
+ expect(typeof emptyObj === 'object').to.equal(true);
+ expect(emptyObj.length).to.equal(undefined); // Object는 length 사용 불가
+
+ 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);
+ expect(megalomaniac.mastermind).to.equal('Joker');
+ expect(megalomaniac.henchwoman).to.equal('Harley');
+ expect(megalomaniac.henchWoman).to.equal(undefined);
+ 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');
+ });
+
+ it('Object의 속성(property)를 다루는 방법을 확인합니다.', function () {
+ const megalomaniac = { mastermind: 'Agent Smith', henchman: 'Agent Smith' };
+
+ expect('mastermind' in megalomaniac).to.equal(true);
+
+ megalomaniac.mastermind = 'Neo';
+ expect(megalomaniac['mastermind']).to.equal('Neo');
+
+ expect('secretary' in megalomaniac).to.equal(false);
+
+ megalomaniac.secretary = 'Agent Smith';
+ expect('secretary' in megalomaniac).to.equal(true);
+
+ delete megalomaniac.henchman;
+ expect('henchman' in megalomaniac).to.equal (false);
+ });
+
+ it("'this'는 method를 호출하는 시점에 결정됩니다.", function () {
+ 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;
+ },
+ };
+ // this -> new Date() 현재 년도 날짜 시간 분 나옴
+ expect(currentYear).to.equal(2024);
+ expect(megalomaniac.calculateAge(currentYear)).to.equal(54);
+
+ megalomaniac.birthYear = 2000;
+ expect(megalomaniac.calculateAge(currentYear)).to.equal(24);
+
+ megalomaniac.changeBirthYear(2010);
+ expect(megalomaniac.calculateAge(currentYear)).to.equal(14);
+
+ /**
+ * !!Advanced [this.mastermind]? this.birthYear? this가 무엇일까요?
+ *
+ * method는 '어떤 객체의 속성으로 정의된 함수'를 말합니다. 위의 megalomaniac 객체를 예로 든다면,
+ * getMembers는 megalomaniac 객체의 속성으로 정의된 함수인 '메소드'라고 할 수 있습니다. megalomaniac.getMembers()와 같은 형태로 사용(호출)할 수 있죠.
+ * 사실은, 전역 변수에 선언한 함수도 웹페이지에서 window 객체의 속성으로 정의된 함수라고 할 수 있습니다.
+ * window. 접두사 없이도 참조가 가능하기 때문에(window.foo()라고 사용해도 됩니다.), 생략하고 쓰는 것뿐입니다. 이렇듯, method는 항상 '어떤 객체'의 method입니다.
+ * 따라서 호출될 때마다 어떠한 객체의 method일 텐데, 그 '어떠한 객체'를 묻는 것이 this입니다.
+ * 예시로, obj이라는 객체 안에 foo라는 메서드를 선언하고, this를 반환한다고 했을 때 ( 예: let obj = {foo: function() {return this}}; )
+ * obj.foo() === obj 이라는 코드에 true라고 반환할 것입니다.
+ * this는 함수의 호출에 따라서 값이 달라지기도 합니다. (apply나 call, bind에 대해서는 하단의 학습자료를 통해 더 공부해 보세요.)
+ *
+ * 그러나 화살표 함수는 다릅니다. 자신의 this가 없습니다.
+ * 화살표 함수에서의 this는 자신을 감싼 정적 범위(lexical context)입니다. (전역에서는 전역 객체를 가리킵니다.)
+ * 일반 변수 조회 규칙(normal variable lookup rules)을 따르기 때문에, 현재 범위에서 존재하지 않는 this를 찾을 때, 화살표 함수 바로 바깥 범위에서 this를 찾습니다.
+ * 그렇기에 화살표 함수를 사용할 때, 이러한 특이점을 생각하고 사용해야 합니다.
+ *
+ * 이와 관련하여, this에 대해서 더 깊이 학습하셔도 좋습니다.
+ * 가이드가 될 만한 학습자료를 첨부합니다.
+ * https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
+ */
+ });
+
+ it('객체의 method를 정의하는 방법을 확인합니다.', function () {
+ const megalomaniac = {
+ mastermind: 'Brain',
+ henchman: 'Pinky',
+ getFusion: function () {
+ return this.henchman + this.mastermind;
+ },
+ battleCry(numOfBrains) {
+ return `They are ${this.henchman} and the` + ` ${this.mastermind}`.repeat(numOfBrains);
+ },
+ };
+
+ expect(megalomaniac.getFusion()).to.deep.equal('PinkyBrain');
+ expect(megalomaniac.battleCry(3)).to.deep.equal('They are Pinky and the Brain Brain Brain');
+ });
+
+ 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';
+ }
+ 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]);
+
+ 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);
+
+ /*
+ 마지막 테스트 코드의 결과가 예상과는 달랐을 수도 있습니다.
+ 'Object.assign'을 통한 복사는 reference variable은 주소만 복사하기 때문입니다.
+ 이와 관련하여 얕은 복사(shallow copy)와 깊은 복사(deep copy)에 대해서 학습하시기 바랍니다.
+ 가이드가 될 만한 학습자료를 첨부합니다.
+ https://scotch.io/bar-talk/copying-objects-in-javascript
+ https://medium.com/watcha/깊은-복사와-얕은-복사에-대한-심도있는-이야기-2f7d797e008a
+ */
+ });
+});
diff --git a/09_SpreadSyntax.js b/09_SpreadSyntax.js
new file mode 100644
index 0000000..793ec93
--- /dev/null
+++ b/09_SpreadSyntax.js
@@ -0,0 +1,122 @@
+describe('Spread syntax에 대해 학습합니다.', function () {
+ it('전개 문법(spread syntax)을 학습합니다.', function () {
+ const spread = [1, 2, 3];
+ // TODO: 전개 문법을 사용해 테스트 코드를 완성합니다. spread를 지우지 않고 해결할 수 있습니다.
+ const arr = [0, spread, 4];
+ expect(arr).to.deep.equal([0, [1, 2, 3], 4]);
+ });
+
+ it('빈 배열에 전개 문법을 사용할 경우, 아무것도 전달되지 않습니다.', function () {
+ const spread = [];
+ // TODO: 전개 문법을 사용해 테스트 코드를 완성합니다. spread를 지우지 않고 해결할 수 있습니다.
+ const arr = [0, spread, 1];
+ expect(arr).to.deep.equal([0, [], 1]);
+ });
+
+ it('여러 개의 배열을 이어붙일 수 있습니다.', function () {
+ const arr1 = [0, 1, 2];
+ const arr2 = [3, 4, 5];
+ const concatenated = [...arr1, ...arr2];
+ expect(concatenated).to.deep.equal([0, 1, 2, 3, 4, 5]);
+ // 아래 코드도 같은 동작을 수행합니다.
+ // arr1.concat(arr2);
+ });
+
+ it('여러 개의 객체를 병합할 수 있습니다.', function () {
+ const fullPre = {
+ cohort: 7,
+ duration: 4,
+ mentor: 'hongsik',
+ };
+
+ const me = {
+ time: '0156',
+ status: 'sleepy',
+ todos: ['coplit', 'koans'],
+ };
+
+ const merged = ({...fullPre, ...me});
+ // 변수 'merged'에 할당된 것은 'obj1'과 'obj2'의 value일까요, reference일까요?
+ // 만약 값(value, 데이터)이 복사된 것이라면, shallow copy일까요, deep copy일까요?
+
+ expect(merged).to.deep.equal({
+ cohort: 7,
+ duration: 4,
+ mentor: 'hongsik',
+ time: '0156',
+ status: 'sleepy',
+ todos: ['coplit', 'koans'],
+ });
+ });
+
+ it('Rest Parameter는 함수의 전달인자를 배열로 다룰 수 있게 합니다.', function () {
+ // 자바스크립트는 (named parameter를 지원하지 않기 때문에) 함수 호출 시 전달인자의 순서가 중요합니다.
+ function returnFirstArg(firstArg) {
+ return firstArg;
+ }
+ expect(returnFirstArg('first', 'second', 'third')).to.equal('first');
+
+ function returnSecondArg(firstArg, secondArg) {
+ return secondArg;
+ }
+ expect(returnSecondArg('only give first arg')).to.equal(undefined);
+
+ // rest parameter는 spread syntax를 통해 간단하게 구현됩니다.
+ function getAllParamsByRestParameter(...args) {
+ return args;
+ }
+
+ // arguments를 통해 '비슷하게' 함수의 전달인자들을 다룰 수 있습니다. (spread syntax 도입 이전)
+ // arguments는 모든 함수의 실행 시 자동으로 생성되는 '객체'입니다.
+ function getAllParamsByArgumentsObj() {
+ return arguments;
+ }
+
+ const restParams = getAllParamsByRestParameter('first', 'second', 'third');
+ const argumentsObj = getAllParamsByArgumentsObj('first', 'second', 'third');
+
+ 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']);
+
+ // arguments와 rest parameter를 통해 배열로 된 전달인자(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);
+ expect(Array.isArray(argumentsObj)).to.deep.equal(false);
+
+ const argsArr = Array.from(argumentsObj);
+ expect(Array.isArray(argsArr)).to.deep.equal(true);
+ expect(argsArr).to.deep.equal('first', 'second', 'third');
+ expect(argsArr === restParams).to.deep.equal(false);
+ });
+
+ it('Rest Parameter는 전달인자의 수가 정해져 있지 않은 경우에도 유용하게 사용할 수 있습니다.', function () {
+ function sum(...nums) {
+ let sum = 0;
+ for (let i = 0; i < nums.length; i++) {
+ sum = sum + nums[i];
+ }
+ return sum;
+ }
+ expect(sum(1, 2, 3)).to.equal(6);
+ expect(sum(1, 2, 3, 4)).to.equal(10);
+ });
+
+ it('Rest Parameter는 전달인자의 일부에만 적용할 수도 있습니다.', function () {
+ // rest parameter는 항상 배열입니다.
+ function getAllParams(required1, required2, ...args) {
+ return [required1, required2, args];
+ }
+ expect(getAllParams(123)).to.deep.equal([123, undefined, []]);
+
+ function makePizza(dough, name, ...toppings) {
+ const order = `You ordered ${name} pizza with ${dough} dough and ${toppings.length} extra toppings!`;
+ return order;
+ }
+ expect(makePizza('original')).to.equal(`You ordered undefined pizza with original dough and 0 extra toppings!`);
+ expect(makePizza('thin', 'pepperoni')).to.equal(`You ordered pepperoni pizza with thin dough and 0 extra toppings!`);
+ expect(makePizza('napoli', 'meat', 'extra cheese', 'onion', 'bacon')).to.equal(`You ordered meat pizza with napoli dough and 3 extra toppings!`);
+ });
+});
diff --git a/10_Destructuring.js b/10_Destructuring.js
new file mode 100644
index 0000000..134d5c4
--- /dev/null
+++ b/10_Destructuring.js
@@ -0,0 +1,137 @@
+describe('구조 분해 할당(Destructuring Assignment)에 관해서', () => {
+ it('배열을 분해합니다', () => {
+ const array = ['java', 'spring', 'im', 'course']
+
+ const [first, second] = array
+ expect(first).to.eql('java')
+ expect(second).to.eql('spring')
+
+ const result = []
+ function foo([first, second]) {
+ result.push(second)
+ result.push(first)
+ }
+
+ foo(array)
+ expect(result).to.eql(['spring', 'java'])
+ })
+
+ it('rest/spread 문법을 배열 분해에 적용할 수 있습니다', () => {
+ const array = ['java', 'spring', 'im', 'course']
+ const [start, ...rest] = array
+ expect(start).to.eql('java')
+ expect(rest).to.eql(['spring', 'im', 'course'])
+
+ // 다음과 같은 문법은 사용할 수 없습니다. 할당하기 전 왼쪽에는, rest 문법 이후에 쉼표가 올 수 없습니다
+ // const [first, ...middle, last] = array
+ })
+
+ it('객체의 단축(shorthand) 문법을 익힙니다', () => {
+ const name = '김코딩'
+ const age = 28
+
+ const person = {
+ name,
+ age,
+ level: 'Junior',
+ }
+ expect(person).to.eql({name: '김코딩', age: 28, level: 'Junior'})
+ })
+
+ it('객체를 분해합니다', () => {
+ const student = { name: '박해커', major: '물리학과' }
+
+ const { name } = student
+ expect(name).to.eql('박해커')
+ })
+
+ it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #1', () => {
+ const student = { name: '최초보', major: '물리학과' }
+ const { name, ...args } = student
+
+ expect(name).to.eql('최초보')
+ expect(args).to.eql({major: '물리학과'})
+ })
+
+ it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #2', () => {
+ const student = { name: '최초보', major: '물리학과', lesson: '양자역학', grade: 'B+' }
+
+ function getSummary({ name, lesson: course, grade }) {
+ return `${name}님은 ${grade}의 성적으로 ${course}을 수강했습니다`
+ }
+
+ expect(getSummary(student)).to.eql('최초보님은 B+의 성적으로 양자역학을 수강했습니다')
+ })
+
+ it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #3', () => {
+ const user = {
+ name: '김코딩',
+ company: {
+ name: 'Javascript',
+ department: 'Development',
+ role: {
+ name: 'Software Engineer'
+ }
+ },
+ age: 35
+ }
+// {
+// name: '박해커',
+// company: {
+// name: 'Javascript',
+// department: 'Development',
+// role: {
+// name: 'Software Engineer'
+// }
+// },
+// age: 20
+// }
+ const changedUser = {
+ ...user,
+ name: '박해커',
+ age: 20
+ }
+
+ const overwriteChanges = {
+ name: '박해커',
+ age: 20,
+ ...user
+ }
+ // const user = {
+ // name: '김코딩',
+ // company: {
+ // name: 'Javascript',
+ // department: 'Development',
+ // role: {
+ // name: 'Software Engineer'
+ // }
+ // },
+ // age: 35
+ // }
+
+ const changedDepartment = {
+ ...user,
+ company: {
+ ...user.company,
+ department: 'Marketing'
+ }
+ }
+ // const user = {
+ // name: '김코딩',
+ // company: {
+ // name: 'Javascript',
+ // department: 'Marketing',
+ // role: {
+ // name: 'Software Engineer'
+ // }
+ // },
+ // age: 35
+ // }
+
+ expect(changedUser).to.eql(FILL_ME_IN)
+
+ expect(overwriteChanges).to.eql(FILL_ME_IN)
+
+ expect(changedDepartment).to.eql(FILL_ME_IN)
+ })
+})