객체란...?

자바스크립트는 객체기반의 프로그래밍 언어이며, 자바스크립트를 구성하는 거의 "모든 것"이 객체이다. (원시값 제외!)

  • 원시 타입은 단 하나의 값만 가지지만 객체는 다양한 타입의 값을 가진다.
  • 원시 타입의 값, 즉 원시 값은 변경 불가능한 값이지만, 객체 타입의 값, 즉 객체는 변경 가능한 값이다.


프로퍼티: 객체의 상태를 나타내는 값
메서드: 프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메서드라 부른다.

자바스크립트에서 함수와 객체는 분리해서 생각할 수 없는 개념이다. 즉, 객체를 이해해야 함수를 제대로 이해할 수 있고, 반대로 함수를 이해해야 객체를 완전히 이해할 수 있다.
객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임을 객체지향 프로그램이라고 한다.

객체 리터럴에 의한 객체 생성

자바스크립트에서 객체 생성 방법

객체 리터럴
Object 생성자 함수
생성자 함수
Object.create 메서드
클래스(ES6)

  • 객체리터럴은 객체를 생성하기 위한 표기법이다.
  • 자바스크립트의 유연함과 강력함을 대표하는 객체 생성 방식이다.
  • (주의) 객체 리터럴의 중괄호는 코드블록을 의미하지 않는다!!!
  • 코드 블록의 닫는 중괄호 뒤에는 세미클론이 붙지않는다. 하지만 객체리터럴은 세미클론이 붙는다.
  • 프로퍼티를 포함시켜 객체를 생성함과 동시에 프로퍼티를 만들 수도 있고, 객체를 생성한 이후에 프로퍼티를 동적으로 추가할 수도 있다.

프로퍼티

객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.

let person = {
	// 프로퍼티 키는 name, 프로퍼티 값은 "Park"
    name: "Park",
    // 프로퍼티 키는 age, 프로퍼티 값은 27
    age: 27
};
let obj = {};
let key = "hello";

// ES5: 프로퍼티 키 동작 생성
obj[key] = "world";
// ES6: 계산된 프로퍼티 이름
// let obj = { [key]: 'world' };

console.log(obj); // {hello: "world"}
  • 접근 - 프로퍼티에 접근하는 방법은 두가지가 있다.
    • 마침표 프로터피 접근 연산자(.)를 사용하는 마침표 표기법.
    • 대괄호 프로퍼티 접근 연산자([...])를 사용하는 대괄호 표기법.
let person = {
    name: "Park",
};

console.log(person.name); // Park
console.log(person["name"]); // Park
  • ES6에서 추가된 객체 리터럴의 확장 기능
  1. 프로퍼티 축약 표현
let x = 1; y = 2;

const obj = {x, y};

console.log(obj); // {x: 1, y: 2}
  1. 계산된 프로퍼티 이름
const prefix = "prop";
let i = 0;

const obj = {
	[`${prefix}-${++i}`]: i,
    [`${prefix}-${++i}`]: i,
    [`${prefix}-${++i}`]: i
};

console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3};

메서드

프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메서드라 부른다. 즉, 메서드는 객체에 묶여 있는 함수이다.

let circle = {
	radius: 5, // 프로퍼티
    
    // 원의 지름
    getDiameter: function() { // 메서드
    	return 2 * this.radius; // this는 circle을 가리킨다.
    };
    
    console.log(circle.getDiameter()); // 10

메서드 내부에서의 this는 객체 자신을 가리키는 참조 변수다.

  • 메서드 축약 표현
const obj = {
	name: 'Park',
    sayHi() {
    	console.log('Hi! ' + this.name); 
    }
};

obj.sayHi(); // Hi ! Park

원시 값과 객체의 비교

  • 원시 값은 변경 불가능한 값이다. 이에 비해 객체(참조) 타입의 값, 즉 객체는 변경 가능한 값이다.
  • 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장된다. 이에 비해 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.
  • 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달이라한다.
  • 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이름 참조에 의한 전달이라한다.

    변경 불가능하다는 것은 변수가 아니라 값에 대한 진술이다.
    원시 값은 변경 불가 ! 즉 읽기 전용 값 !

// const 키워드를 사용해 선언한 변수는 재할당이 금지된다. 상수는 재할당이 금지된 변수일 뿐이다.
const o = {};

// const 키워드를 사용해 선언한 변수에 할당한 원시 값(상수)은 변경할 수 없다.
// 하지만 const 키워드를 사용해 선언한 변수에 할당한 객체는 변경할 수 있다.
o.a = 1;
console.log(o); // {a: 1}

값에 의한 전달 (원시 값)

1)

let score = 80;
let copy = score;

console.log(score); //80
console.log(copy); // 80

score = 100;
console.log(score); // 100
console.log(copy); // 80

2)

let score = 80;
let copy = score;

console.log(score, copy); // 80 80
console.log(score === copy); // true

이때 score 변수와 copy변수 의 값 80은 다른 메모리 공간에 저장된 별개의 값이다.

3)

let score = 80;
let copy = score;

console.log(score, copy); // 80 80
console.log(score === copy); // true

score = 100;

console.log(score, copy); // 100 80
console.log(score === copy); // false;

참조에 의한 전달

1)

let person = {
	name: 'Park'
};

객체를 할당한 변수를 참조하면 메모리에 저장되어 있는 참조 값을 통해 실제 객체에 접근한다.
업로드중..
2) 얕은 복사 깊은 복사

객체를 프로퍼티 값으로 갖는 객체의 경우 얕은 복사는 한 단계까지만 복사하는 것을 말하고 깊은 복사는 객체에 중첩되어 있는 객체까지 모두 복사하는 것을 말한다.

const o = { x: { y: 1} };

// 얕은 복사
const c1 = {...o};
console.log(c1 === o); // false
console.log(c1.x === o.x); // true
const v = 1;

// 깊은 복사
const c1 = v;
console.log(c1 === v); // true

const o = { x: 1};

// 얖은 복사
const c2 = o;
console.log(c2 === o); // true

3) 참조에 의한 전달

let person = {
	name: 'Park'
};

// 참조 값을 복사 (얕은 복사)
let copy = person;
  • 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사 되어 전달된다.
  • 두 개의 식별자가 하나의 객체를 공유한다.

업로드중..

Quiz) 다음을 실행하면 1번과 2번은 뭐가 출력될까?

let person1 = {
	name: 'Park'
};

let person2 = {
	name: 'Park'
};

console.log(person1 === person2); 1번
console.log(person1.name === person2.name); 2

정답: 1번은 false. 2번은 true이다.
이유는 person1과 person2의 내용을 같지만 서로가 다른 메모리에 저장되어 있기 때문에 참조 값은 전혀 다르므로 1번은 false 이다.
프로퍼티 값을 참조하는 person1.name과 person2.name은 값으로 평가될 수 있는 표현식이므로 두 표현식의 원시 값은 'Park'이므로 true이다.

함수란?

  • 함수는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다.
  • 자바스크립트에서 함수는 객체다.

함수 정의 방식

  • 선언문
    함수 선언문은 함수 이름을 생략할 수 없다.
function add(x, y) {
	return x + y;
}
let add = function add(x, y) {
	return x + y;
};

console.log(add(2, 5)); // 7

자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당한다.
함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.

  • 표현식
    함수 리터럴의 함수 이름 생략 가능
const add = function(x, y) {
	return x + y;
}
  • 생성자 함수
const add = new Function('x', 'y', 'return x + y');
  • 화살표 함수(ES6)
const add = (x, y) => x + y;

호이스팅

함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다르다.

다양한 함수의 형태

  • 즉시실행 함수
    함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행하는 것이고 함수는 단 한번만 호출되며 다시 호출할 수 없다.
(function () {
	let a = 3;
    let b = 5;
    return a + b;
}());
  • 재귀 함수
    함수가 자기 자신을 호출하는 것이다.
function countdown(n){
	if (n < 0) return;
    console.log(n);
    countdown(n - 1); // 재귀호출
}

countdown(10);
  • 중첩 함수
    함수 내부의 정의된 함수, 중첩 함수는 중첩 함수를 포함하는 외부 함수내부에서만 호출 가능하다.
    일반적으로 중첩함수는 자신을 포함하는 외부함수를 돕는 헬퍼함수다.
function outer() {
	let x = 1;

function inner() {
	let y = 2;
	console.log(x + y); // 3
	}
	
    inner();
}

outer();
  • 콜백 함수
    함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수이다.
function introduce (lastName, firstName, callback) { 
	let fullName = lastName + firstName; 
	callback(fullName); 
} 

introduce ("박", "경빈", function (name) { 
	console.log(name); 
};

// 결과 -> 박경빈
  • 순수 함수와 비순수 함수
    함수의 외부 상태를 변경하지 않으므로 Side Effect를 막는다.
    상태 변화를 추적하기가 쉽다.
// 비 순수함수
let count = 0;
function increase(n) {
	return ++count; // 외부 상태에 의존
}

increase();
console.log(count); // 1

increase();
console.log(count); // 2
// 순수함수
let count = 0;
function increase(n) {
	return ++n;
}

count = increase(count);
console.log(count); // 1

count = increase(count);
console.log(count); // 2
profile
꺾여도 하는 마음

0개의 댓글