-
[모던자바스크립트 DeepDive] 10~12장개발일기/자바스크립트 2024. 8. 11. 15:28
10장 - 객체리터럴
10.1 객체란?
📌 자바스크립트는 객체 기반의 프로그래밍 언어이며, 자바스크립트를 구성하는 거의 "모든 것" 이 객체다.
📌 원시 값을 제외한 나머지 값(함수, 배열, 정규 표현식 등)은 모두 객체다.
✅ 객체의 구조
· 객체는 키(key)와 값(value)으로 구성되어 있는 집합체다.
· 프로퍼티: 객체의 상태를 나타내는 값(data)
· 메서드: 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작(behavior)
const counter = { num: 0, // 프로퍼티 increase: () => { // 메서드 this.num++; } };
10.2 객체 리터럴에 의한 객체 생성
📌 자바스크립트는 프로토타입 기반 객체지향 언어로서 다양한 객체 생성 방법을 지원한다.
· 객체 리터럴 -> 가장 일반적인 방법
· Object 생성자 함수
· 생성자 함수
· Object.create 메서드
· 클래스(ES6)
✅ 객체 리터럴에 의한 객체 생성방법
const person = { name: 'dayo', sayHello: function () { console.log(`Hello! My name is ${this.name}.`); } }; console.log(typeof person); // object console.log(person); // {name: 'dayo', sayHello: f} let empty = {}; // 빈 객체 console.log(typeof empty); // object
10.3 프로퍼티📌 객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.
· 프로퍼티 키: 빈 문자열을 포함하는 모든 문자열 또는 심벌 값
· 프로퍼티 값: 자바스크립트에서 사용할 수 있는 모든 값
const person = { // 프로퍼티 키는 name, 프로퍼티 값은 'Dayo' name: 'Dayo', // 프로퍼티 키는 age, 프로퍼티 값은 20 age: 20 };
💁🏻 프로퍼티 키로 숫자 리터럴을 사용하면 따옴표는 붙지 않지만 내부적으로는 암묵적 타입 변환을 통해 문자열이 된다.
10.4 메서드📌 자바스크립트의 함수는 객체(일급 객체)다. 따라서 함수는 값으로 취급할 수 있기 때문에 프로퍼티 값으로 사용 가능하다.
📌 프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해서 메서드라 부른다. 즉, 메서드는 객체에 묶여있는 함수를 의미
const circle = { // 프로퍼티 radius: 5, // 메서드 getDiameter: () => { return 2 * this.radius; } }; console.log(circle.getDiameter()); // 10
10.5 프로퍼티 접근📌 프로퍼티에 접근하는 방법은 두 가지다.
· 마침표 프로퍼티 접근 연산자(.)를 사용하는 마침표 표기법
· 대괄호 프로퍼티 접근 연산자([...])를 사용하는 대괄호 표기법
const person = { name: 'Dayo' }; // 마침표 표기법에 의한 프로퍼티 접근 console.log(person.name); // 'Dayo' // 대괄호 표기법에 의한 프로퍼티 접근 console.log(person['name']); // 'Dayo'
✅ 대괄호 표기법 접근시, 대괄호 내부 프로퍼티 값에 문자열('name')을 넣어야 하는것에 유의
10.6 프로퍼티 값 갱신📌 이미 존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신된다.
const person = { name: 'Dayo' }; // person 객체에 name 프로퍼티가 존재하므로 name 프로퍼티 값이 갱신된다. person.name = 'Yoda'; console.log(person); // { name: 'Yoda' }
10.7 프로퍼티 동적 생성📌 존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 동적으로 생성되어 추가되고 프로퍼티 값이 할당 된다.
const person = { name: 'Dayo' }; // person 객체에는 age 프로퍼티가 존재하지 않는다. // 따라서 person 객체에 age 프로퍼티가 동적으로 생성되고 값이 할당된다. person.age = 20; console.log(person); // { name: 'Dayo', age: 20 }
10.8 프로퍼티 삭제
📌 delete 연산자는 객체의 프로퍼티를 삭제한다. 존재하지 않는 프로퍼티를 삭제하면 아무런 에러 없이 무시된다.
const person = { name: 'Dayo' }; // 프로퍼티 동적 생성 person.age = 20; // delete 연산자로 age 프로퍼티를 삭제 delete person.age; // delete 연산자로 존재하지 않는 프로퍼티인 address를 삭제하지만 아무런 일도 일어나지 않는다.(에러 발생X) delete person.address; console.log(person); // { name: 'Dayo' }
10.9 ES6에서 추가된 객체 리터럴의 확장 기능📌 프로퍼티 축약 표현(ES6)
· 프로퍼티 값으로 변수를 사용하는 경우 변수 이름과 프로퍼티 키가 동일한 이름일 때 프로퍼티 키를 생략할 수 있다.
let x = 1; let y = 2; const obj = { x, y }; console.log(obj); // { x: 1, y: 2 }
· ES6에서는 메서드를 정의할 때 function 키워드를 생략한 축약 표현을 사용할 수 있다.
// ES5 const obj = { name: 'Dayo', sayHi: function() { console.log(`Hi! ${this.name}`); } }; obj.sayHi(); // Hi! Dayo // ES6 const obj = { name: 'Dayo', sayHi() { console.log(`Hi! ${this.name}`); } }; obj.sayHi(); // Hi! Dayo
✅ 메서드 축약 표현으로 정의한 메서드는 프로퍼티에 할당한 함수와 다르게 동작한다 26.2절 '메서드' 에서 자세히 설명.
11장 - 원시 값과 객체의 비교
✅ 원시 타입과 객체 타입의 3가지 다른 측면
- 원시 타입의 값은 변경 불가능한 값이며 객체 타입의 값은 변경 가능한 값이다.
- 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장된다. 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.
- 원시 값을 갖는 변수를 다른 변수에 할당하면 원시 값이 복사되어 전달된다. 객체를 가리키는 변수를 다른 변수에 할당하면 참조 값이 복사되어 전달된다.11.1 원시 값
1. 원시 값은 변경 불가능한 값이다. (불변성)
따라서, 변수 값을 변경하기 위해 원시 값을 재할당하면 새로운 메모리 공간을 확보하고 재할당한 값을 저장한 후, 변수가 참조하던 메모리 공간의 주소를 변경한다.
2. 문자열과 불변성
let str = 'Hello'; str = 'World';
위 코드에서 문자열은 불변성을 갖기 때문에, 두 번째 문이 실행되면 Hello를 수정하는 것이 아니라 새로운 문자열 World를 메모리에 생성하고 식별자 str은 이것을 가리킨다.
let str = 'string'; // 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근할 수 있다. // 하지만 문자열은 원시 값이므로 변경할 수 없다. 이때 에러가 발생하지 않는다. str[0] = 'S'; console.log(str); // string;
원시 값은 어떤일이 있어도 불변한다.
3. 값에 의한 전달let score = 80; // copy 변수에는 score 변수의 값 80이 복사되어 할당된다. let copy = score; console.log(score, copy); // 80 80 console.log(score === copy); // true // score 변수와 copy 변수의 값은 다른 메모리 공간에 저장된 별개의 값이다. // 따라서 score 변수의 값을 변경해도 copy 변수의 값에는 어떠한 영향도 주지 않는다. score = 100; console.log(score, copy); // 100 80 console.log(score === copy); // false
값에 의한 전달을 통한 복사는 같은 값을 갖는다는 점은 동일하지만, 서로 다른 메모리 공간에 저장된 별개의 값이다.
📌 두 변수의 원시 값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭할 수 없다.
11.2 객체1. 변경 가능한 값
객체(참조) 타입의 값, 객체는 변경 가능한 값이다. 객체를 할당한 변수는 객체의 값을 갖는것이 아닌 메모리 공간에 접근할 수 있는 참조 값(메모리 공간의 주소)을 저장한다. 따라서 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다.
let person = { name: 'Dayo' }; // 프로퍼티 값 갱신 person.name = 'Yoda'; // 프로퍼티 동적 생성 person.address = 'Seoul'; console.log(person); // {name: 'Yoda', address: 'Seoul'}
2. 참조에 의한 전달
let person = { name: 'Dayo' }; // 참조 값을 복사(얕은 복사). copy와 person은 동일한 참조 값(메모리 주소)을 공유한다. let copy = person; // copy와 person은 동일한 객체를 참조한다. console.log(copy === person); // true // copy를 통해 객체를 변경 copy.name = 'Yoda'; // person을 통해 객체를 변경 person.address = 'Seoul'; console.log(person); // {name: 'Yoda', address: 'Seoul'} console.log(copy); // {name: 'Yoda', address: 'Seoul'}
📌 객체의 복사는 메모리 공간에 저장되어 있는 값(참조하고 있는 값의 주소)을 전달해주기 때문에 어느 한쪽에서 객체를 변경하더라도 서로 영향을 주고받는다.
12장 - 함수
12.1 함수란?
📌 프로그래밍 언어의 함수는 일련의 과정을 문(statement)으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다.
함수 내부로 입력을 전달받는 변수를 매개변수(parameter), 입력을 인수(argument). 출력을 반환값(return value)이라 한다.
12.2 함수를 사용하는 이유📌 함수는 필요할 때 여러 번 호출할 수 있다. 실행 시점을 개발자가 결정할 수 있고, 재사용이 가능하다.
함수를 사용하지 않고 같은 코드를 중복해서 여러 번 작성하면 그 코드를 수정해야 할 때 중복된 횟수만큼 코드를 수정해야 한다.
하지만 함수를 사용하면 코드의 중복을 억제하고 유지보수의 편의성을 높이고 실수를 줄여 코드의 신뢰성을 높이는 효과가 있다.
12.3 함수 리터럴📌 자바스크립트의 함수는 객체 타입의 값이다. 함수 리터럴은 function 키워드, 함수 이름, 매개 변수, 함수 몸체로 구성된다.
📌 함수는 객체지만 일반 객체와는 다르다. 일반 객체는 호출할 수 없지만 함수는 호출할 수 있다.// 변수에 함수 리터럴을 할당 const f = function add(x,y) { return x + y; }
12.4 함수 정의📌 함수 정의란 함수를 호출하기 이전에 인수를 전달받은 매개변수와 실행할 문들, 그리고 반환할 값을 지정하는 것을 말한다.
// 함수 선언문 function add(x,y) { return x + y; } // 함수 표현식 const add = function (x,y) { return x + y; } // Function 생성자 함수 const add = new Function('x', 'y', 'return x + y'); // 화살표 함수(ES6) const add = (x, y) => x + y;
✅ 함수 생성 시점과 함수 호이스팅
- 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출 할 수 있지만, 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.
- 함수 선언문이 코드의 선두로 끌어 오려진 것처럼 동작하는 자바스크립트 고유의 특징을 함수 호이스팅이라 한다.
- 함수 선언문 대신 함수 표현식을 사용할 것을 권장한다.// 함수 참조 console.dir(add(2,5)); // f add(x,y) console.dir(sub(2,5)); // undefined // 함수 호출 console.log(add(2,5)); // 7 console.log(sub(2,5)); // TypeError: sub is not a function // 함수 선언문 function add(x, y) { return x + y; } // 함수 표현식 const sub = function (x, y) { return x - y; }
12.5 함수 호출📌 함수는 함수를 가리키는 식별자와 한 쌍의 소괄호인 함수 호출 연산자로 호출한다.
- 매개변수는 함수를 정의할 때 선언하며, 함수 내부에서 변수와 동일하게 취급된다. 즉 매개변수는 함수 내부 scope를 갖는다.
- 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않는다.
- 자바스크립트는 동적 타입 언어이기 때문에 매개변수의 타입을 사전에 지정할 수 없다. ( 타입스크립트 사용 권장 )
12.6 참조에 의한 전달과 외부 상태의 변경✅ 매개변수도 함수 내부에서 변수와 동일하게 취급되므로 매개변수 또한 타입에 따라 값에 의한 전달, 참조에 의한 전달 방식을 그대로 따른다.
// 매개변수는 primitive는 원시 값, 매개변수 obj는 객체(참조)를 전달받는다. function changeVal(primitive, obj) { primitive += 100; obj.name = 'Yoda'; } // 외부 상태 let num = 100; let person = { name: 'Dayo' }; console.log(num); // 100; console.log(person); // { name: 'Dayo' } changeVal(num, person); // 원시 값은 원본이 훼손되지 않는다. console.log(num); // 100; // 객체(참조) 값은 원본이 훼손된다. console.log(person); // { name: 'Yoda' }
📌 외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 함수를 순수 함수라 한다. 순수 함수를 통해 부수효과를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이려는 프로그래밍 패러다임을 함수형 프로그래밍이라 한다.
12.7 다양한 함수의 형태1. 즉시 실행 함수
- 함수 정의와 동시에 즉시 호출되는 함수.
- 즉시 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없다.
(function foo () { const a = 3; const b = 5; return a * b; }()); foo(); // ReferenceError: foo is not defined
- 재귀 함수는 자기 자신을 호출하는 행위, 즉 재귀 호출을 수행하는 함수를 말한다.
- 재귀 함수는 반복되는 처리를 반복문 없이 구현할 수 있다는 장점이 있지만 무한 반복에 빠지 위험이 있고, 이로 인해 스택 오버플로 에러를 발생시킬 수 있으므로 주의해서 사용해야 한다.
- 재귀 함수는 반복문을 사용하는 것보다 재귀 함수를 사용하는 편이 더직관적으로 이해하기 쉬울 때만 한정적으로 사용하는 것이 바람직하다.
function countdown(n) { for (var i = n; i >= 0; i--) { console.log(i); } } countdwon(10); ///////////////////////////////////////// function countdown(n) { if(n < 0) return; console.log(n); countdown(n-1); // 재귀 호출 } countdwon(10);
3. 중첩 함수
- 함수 내부에 정의된 함수를 중첩 함수(nested function) 또는 내부 함수(inner function)라 한다.
function outer() { let x = 1; // 중첩 함수 function inner() { let y = 2; // 외부 함수의 변수를 참조할 수 있다. console.log(x + y); // 3 } inner(); } outer();
4. 콜백 함수
- 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라고 말한다.
- 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수(Higher-Order Function, HOF)라고 한다.
// 외부에서 전달받은 f(콜백함수)를 n만큼 반복 호출한다. function repeat(n, f) { for(var i = 0; i < n; i++) { f(i); // 인수 i를 전달하면서 f(콜백함수) 호출 } } const logAll = function (i) { console.log(i); }; // 반복 횟수와 호출할 함수(콜백함수)를 인수로 전달 repeat(5, logAll); // 0 1 2 3 4 const logOdds = function (i) { if ( i % 2 ) console.log(i); }; // 반복 횟수와 호출할 함수(콜백함수)를 인수로 전달 repeat(5, logOdds); // 1 3
- 순수 함수: 어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 부수 효과가 없는 함수
- 비순수 함수: 외부 상태에 의존하거나 외부 상태를 변경하는 부수 효과가 있는 함수
/** 순수 함수 */ let count = 0; // 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일한 값을 반환한다. function increase(n) { return ++n; } count = increase(count); console.log(count); // 1 count = increase(count); console.log(count); // 2 /** 비순수 함수 */ let count = 0; function increase() { return ++count; // 외부 상태에 의존하며 외부 상태를 변경한다. } // 비순수 함수는 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어렵다. count = increase(count); console.log(count); // 1 count = increase(count); console.log(count); // 2
'개발일기 > 자바스크립트' 카테고리의 다른 글
[코어 자바스크립트] 서론 (0) 2024.09.21 [모던자바스크립트 Deep Dive] 13~15장 (1) 2024.08.18 [모던자바스크립트 Deep Dive] 7~9장 (0) 2024.08.04 [모던자바스크립트 Deep Dive] 4~6장 (0) 2024.08.03 [모던자바스크립트 Deep Dive] 1~3장 (0) 2024.08.03