객체지향 프로그래밍 - 사람이 실체(사물이나 개념)을 인식하는 철학적 사고를 프로그래밍에 적목시키려는 시도이다.

실체는 성질을 나타내는 속성이 있다. 사람을 예로 들면 이름, 나이, 주소, 키 등등 여러가지가 있을 것이다. 프로그래밍은 그러 여러 속성 중 필요한 속성만 간추려 프로그래밍한다. 그것을 추상화라고 한다. 객체는 상태를 나타내는 데이터 상태와 그 데이터를 조작할 수 있는 동작으로 구성된 복합적인 자료구조이다.

 

상속 - 생성자 함수를 생각해보자. 간편하게 같은 구조의 프로퍼티나 메서드를 가진 객체를 만들 수 있다. 하지만 이런 반복은 결국 낭비가 된다. 그것을 방지하기 위해 부모 객체가 가진 것을 상속하여 불필요한 중복을 제거한다.

 

프로토타입 객체 - 모든 객체는 [[Prototype]] 이라는 내부슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조다. 저장되는 프로토타입은 객체 생성방식에 따라 결정된다.

 

__proto__ 접근자 프로퍼티로 [[Prototype]] 내부슬롯에 간접접근 할 수 있다. 접근자함수이므로 get, set이 있으며 프로토타입을 읽거나 할당한다. __proto__ 는 객체가 직접 소유하는 것이 아닌 Object.prototype의 프로퍼티로 상속 받아 사용할 수 있다. 

 

질문 1) 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유가 뭘까?

 

 

일급객체는 무명의 리터럴로 생성할 수 있다. 즉, 런타임 시 생성 가능하다.(표현식 말하는 것 같다)

변수나 자료구조에 저장가능 하다.

매개변수로 전달 가능하다.

반환값으로 사용 가능하다.

 

함수 객체의 프로퍼티는 argument, caller, length, name, prototype, __proto__ 로 구성된다.

 

argument는 함수 호출 시 전달된 인수들의 정보를 담고 있는 유사 배열 객체이다.

 argumet는 전달받은 인수를 순서대로 저장하며, 매겨변수를 초과해서 받은 인수 역시 저장을 한다. argument의 length 프로퍼티는 인수가 몇개인지 나타낸다. 그렇기 때문에 인수의 개수에 따라 동작을 달리하는 구조를 만들 때 유용하다.

 

caller 프로퍼티는 자신을 호출한 함수를 가리킨다. 호출한 함수가 없다면  null을 반환한다. 

 

lengh는 매개변수의 숫자를 나타낸다. argument의 lengh는 인수의 숫자이므로 주의하자.

 

name 프로퍼티 함수의 이름을 나타낸다. ES5에서는 함수이름이 없다면 빈 문자열을 값으로 받았으나 ES6부터는 함수를 가리키는 식별자를 값으로 같는다.

 

__proto__ 모든 객체는 [[Prototype]] 이라는 내부슬롯을 갖는다. __proto__는 [[Prototype]] 내부슬롯이 가리키는 프로토타입 객체 접근하기 위해 사용하는 접근자 프로퍼티다.

 

prototype 프로퍼티는 생성자 함수로 호출할 수 있는 함수 객체, 즉 constructor 만이 소유하는 객체다. 함수가 객체로 생성될 때 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다. 

 

생성자 함수란 new 연산자오 함께 호출하여 객체(인스턴스)를 생성하는 함수를 말한다.

 

new연산자와  Object 생성자 함수를 사용하면 빈 객체를 만들 수 있다.

Object 말고도 Number, String, Boolean, Function, Array, RegExp, Date 등의 빌트인 생성자 함수가 있다.

 

  • 복습 질문 1) new를 붙이지 않고도 생성자 함수를 생성하는 빌트인 생성자 함수는 무엇일까?

 

생성자 함수를 쓰는 이유는 객체는 편리하지만 값이 다른 같은 구조의 프로퍼티를 가진 객체가 많이 필요할 경우 너무 많은 동일 구조 객체를 많들어야 할 수도 있다. 생성자 함수는 이런 상황을 막아준다.

 

this 바인딩은 인스턴스와 연결 된다. 바인딩이란 식별자와 값을 연결하는 과정을 말하며 this는 인스턴스를 가리키고, 빈 객체에 프로퍼티나 메서드를 추가할 수 있다.

 

  • 복습 질문 2) 생성자 함수가 아닌 함수에서 this를 쓰면 어떻게 될까? 
  • 복습 질문 3) 인스턴스 반환은 어떻게 될까? return 이 있을 때와 없을 때 어떤 차이가 있을까

 

함수 역시 객체이므로 일반 객체가 가진 내부슬롯과 내부메서드를 가진다. 여기서 함수와 일반객체의 차이는 호출이 가능하다는 것이다. 따라서 함수만 가지는 내부슬롯과 내부메서드 [[Call]], [[construct]] 를 가진다. 

 

[[Call]]은 함수 호출을 할 때 호출된다.

[[Construct]]는 생성자 함수로서 호출할 때 호출된다.

 

함수 객체라면 호출 가능하여야 하므로 모두 callable 하며 함수 종류에 따라 constructor 과 non-constuctor로 나뉜다.

 

  • 복습 질문 4) constructor 함수와  non-constuctor은 무엇이 있을까?

 

new.target은 생성자함수로서 호출되었는지 아닌지 확인할 수 있다. 생성자 함수로 호출되었다면 new.target은 함수 자신을 가리킨다. 일반 함수로 호출 되었다면 new.target의 내부는 undefined 이다.

  • 복습 질문 5) new.target을 이용해 생성자 함수인지 검사하고 아니라면 생성자 함수로 만드는 방법은 무엇일까?
  • 복습 질문 6)new.target이 없다면 위의 상황을 어떻게 해결할까?

내부슬롯과 내부메서드는 JS 엔진의 구현 알고리즘을 설명하기 위한 내부로직으로 직접 접근이 불가능하다

일부 내부슬롯과 내부메서드 중에서 간접적으로 접근 가능한 것이 있는데

 

모든 객체는 [[Prototype]] 이라는 내부슬롯을 가지고 __proto__를 통해 간접 접근이 가능하다

 

또 내부슬롯 중 하나인 프로퍼티의 상태를 나타내는 어트리뷰트 역시 Object.getOwnPropertyDescriptor로 간접 접근이 가능하다.

 

프로퍼티의 상태 요소는 일반적으로 값, 갱신가능 여부, 열거가능 여부, 재정의가능 여부를 말한다.

 

프로퍼티의 종류는 데이터 프로퍼티, 접근자 프로퍼티가 있으며, 데이터 프로퍼티는 일반적인 우리가 아는 프로퍼티이고

접근자 프로퍼티는 다른 데이터 프로퍼티를 읽거나, 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티이다.

 

접근자 프로퍼티의 상태 요소는 get, set, 열거가능 여부, 재정의가능 여부 등이 있다. 

 

get은 데이터 프로퍼티에 접근할 때 getter 함수를 호출하여 데이터 프로퍼티의 값을 반환한다.

set은 데이터 프로퍼티에 값을 저장할 때 호출되는 접근자 함수다. 접근자 프로퍼티 키로 데이터 프로퍼티 값을 저장하면 setter 함수가 호출되고 그 결과 프로퍼티 값으로 저장된다.

 

Object.defineProperty 메서드를 사용하면 프로퍼티의 어트리뷰트를 정의, 재정의 할 수 있다.

정의할 때 생략한 어트리뷰트는 value, get, set은 undefined로 writable, enumerable, configurable는 false가 기본값으로 적용된다. 

 

객체변경방지 

 

객체 확장금지 Object.preventExtensions 객체 추가가 금지된다. 삭제, 읽기, 쓰기, 재정의는 가능하다.

객체 밀봉 Object.seal 프로퍼티 추가, 삭제, 재정의가 금지된다. 읽기와 쓰기는 가능하다.

객체 동결 Object.freeze 읽기 외엔 모두 금지된다. 

 

 

 

생성자 함수란 new 연산자와 함께 호출되어 객체를 생성하는 함수를 말한다.

생성자 함수에 의해 생성된 객체를 인스턴스라고 한다.

 

같은 프로퍼티 공유하는 여러 객체를 만들기 쉽다.

 

this 바인딩을 통해 프로퍼티를 만들 수 있다.

 

내부 메서드 [[Call], [[Construct]] 

함수로 호출될 때 Call

생성자 연산자로 호출될 때 Consturct - 메서드, 화살표 함수는 안됨

 

new.target 

new 연산자 ㅇ벗이 호출되는 것을 방지하기 위해 사용한다. 

내부 슬롯, 내부 메서드

 

자바 엔진 알고리즘을 설명하기 위한 의사 슬롯과 의사 메서드이다.

둘다 내부 로직에 관련되어 있어서 직접 접근은 안되고 간접 접근은 가능하다.

[[ ]]으로 나타낸다.

 

 

내부슬롯은 객체를 만들면 객체 안에 [[Prototype]]으로 자동으로 생성된다.

간접접근으로 객체이름.__proto__ 로 접근할 수 있다.

 

어트리뷰트

 

프로퍼티의 상태를 나타내는 프로퍼티로 내부슬롯에 해당된다.

구성은 값, 값의 변경 여부, 열거가능여부, 재정의 가능 여부를 나타낸다.

역시나 직접접근은 안되고 Object.getOwnPropertyDescriptor(객체이름, '키') 로 표현한다.

참조할 객체와 키값을 받으면 디스크립터 객체를 반환한다.

 

프로퍼티의 종류

 

데이터 프로퍼티 - 일반적인 키와 값으로 구성된 우리가 아는 프로퍼티다 

 접근자 어트리뷰트 - 값이 아닌 다른 프로퍼티에 접근하는 접근자 함수로 구성된 프로퍼티 

어트리뷰트도 데이터 프로퍼티랑 다르게 프로퍼티에 읽거나 저장할 때 호출되는 get과  set,

열거가능 여부, 재정의가능 여부로 구성되어있다.

 

Object.defineProperty 매서드를 사용하면 프로퍼티의 어트리뷰트를 정의할 수 있다.

 

객체 변경 방지

 

객체확장금지 - 프로퍼티 추가가 금지되고 나머지는 어트리뷰트는 true다.

 

객체 밀봉 - 프로퍼티 추가, 삭제, 재정의가 금지되고 나머지는 true다.

 

객체 동결 - 읽기 외엔 모두 금지된다. 

함수란 -입력을 받아 출력을 하는 과정을 말한다. 

 

함수의 구성 - 함수이름, 매개변수, 함수몸체, 반환값, 인수로 구성된다.

 

함수의 생성과 실행 - 생성은 정의를 통해 이루어지고 실행은 호출로 이루어진다.

 

함수를 쓰는 이유 - 함수는 재사용하기 매우 편리하다. 그런 측면에서 신뢰성이 높아진다.

함수는 객체이므로 식별자로 표현하고, 식별자 덕분에 의미를 알기 쉽다.

 

함수 리터럴 - 함수이름은 식별자 명명법을 따라야한다 그리고 생략가능하다, 함수 선언문 제외

함수이름은 함수 몸체 내에서만 참조 가능하다.

매개변수 역시 식별자 명명법을 따라야 한다 그리고 매개변수도 없어도 상관없다

 

함수 정의 방법 4가지

 

함수 선언문

함수 표현식 

생성자 함수

화살표 함수

 

함수 선언문의 특징 

 

1. 함수이름과 식별자 - 함수이름은 함수내에서만 참조 가능하다. 그런데 호출이 가능한 이유는

언어차원에서 암묵적으로 함수이름으로 식별자를 만들기 때문이다. 그렇기 때문에 다른 정의법과 다르게

선언문은 이름을 생략해선 안된다.

 

2.문맥에 따라 선언문과, 표현문으로 분별한다. 

선언문은 변수에 할당되지 않지만 표현문을 보면 아닌 것 같다. 그 이유는 JS가 문맥에 따라 다르게 이해하기 때문이다.

선언문이 만약 피연산자가 된다면 표현문으로 본다. 피연산자는 값이어야 가능하므로

 

함수 표현식의 특징

 

1.일급객체이다. 일급 객체는 값으로 표현되는 객체이다. 함수는 값이자 객체이므로 일급객체다

 

2. 선언문과 표현식의 호이스팅 차이 

선언문은 호이스팅 돼서 선언 전에 호출 되더라도 값이 나온다. 표현식 역시 호스팅 되지만 var 변수 호스팅과 같이

undefined로 먼저 호이스팅 되고 표현식을 만나 객체가 할당되므로 차이가 있다.

 

다른 정의문 생성자 함수와 화살표 함수는 뒤에가서 자세히 배운다.

 

함수 인수

 

1. 함수 인수 숫자를 다르게 넣었을 때 

함수 인수를 많이 넣는다면 초과분은 무시하고 적게 넣는다면 add(2, undefined) NaN을 출력한다.

 

2.인수 확인 작업 

JS의 선언 키워드는 타입 가리지 않고 받을 수 있다. 그래서 함수의 기대와 다른 타입을 받을 수 있으므로 확인작업이

필요하다.

 

3.인수를 받는 매개변수 역시 변수다.

인수를 받기 전 호이스팅 되어 undefined를 받고, 함수스코프이다. 

 

return 반환문

 

1.문을 끝내고 값을 반환하는 특징을 가졌다.

 

2. 생략가능하다. 다만 undefine값이 출력된다.

 

 

여러가지 함수

 

1. 즉시 실행 함수 

 

그룹연산자로 묶어서 만든다. 함수리터럴이 되어서 식별자가 없다. 1회 실행된 뒤 호출 불가능이다.

함수이름이 없는 것이 일반적이다. 그룹연산자가 없다면 함수이름이 없어서 에러가 나고, 이름이 있다면

선언문이 되어 자동으로 } 끝에 세미클론이 생겨 () 그룹연산자에 값이 없어 에러가 난다.

일반적으로 그룹연산자로 만드는데 함수리터럴로 평가해서 함수객체를 만들수만 있다면 다른식으로도 가능하다

 

2.재귀함수 

 

함수가 자신을 호출하는 형태 작성자가 원하는 만큼 반복하고 싶을 때 쓴다.

 

3. 고차함수, 콜백함수 

 

함수가 다른 함수를 인수로 받는 경우다. 외부에서 다른 함수를 전달받는 함수를 고차함수,

인수로 다른 함수에 전달되는 함수를 콜백함수라 부른다. 콜백함수가 고차함수에서만 호출된다면 

즉시 실행함수로 일반적으로 구성한다.

 

4.순수, 비순수함수

 

순수함수는 외부환경에 의존하거나 변경하지도 않는 불변성을 지는 함수를 말한다.

비순수 함수는 외부환경에 의존하고 변경되는 함수를 말한다.

 

5. 중첩함수 

 

함수 내부에 정의된 함수로 중첩함수 또는 내부함수로 부른다. 일반적으로 내부함수는 외부함수를 돕는

헬퍼 함수이다. 

 

 

 

 

원시값은 불변이다. 원시값은 상수, 문자열이 있는데 문자열은 배열과 비슷하다. 

그래서 배열처럼 인덱스로 접근할수 있지만 그렇다고 인덱스 값을 변경할 수 있는 것은 아니다.

변수에 할당된 상수를 다른 값을 넣으면 바뀐다 할 수 있겠지만 틀린 말이다.

 

변수에 원시값을 할당하면 매번 새로운 메모리에 담긴다. 변수가 가르키는 메모리 주소가 바뀌는 것이지

메모리에든 상수값은 변하지 않는다.

 

객체는 그럼 어떻게 될까? 변수에 객체를 할당하면 할당된 메모리에 값이 아닌 객체의 주소를 담는다.

변수의 메모리 주소 -> 객체의 값이 담긴 주소 -> 값이 나온다. 

 

원시값의 불변성은 어떤 변수에 원시값을 담고 다른 변수에 그 변수를 할당했을 때 

어떠한 변수의 값을 바꾼다고 해도 다른 값에 영향을 주지 않는다. 그저 새로운 메모리에 담기 때문이다.

 

객체는 아니다. 변수에 객체를 담고 그 변수를 다른 변수에 할당한다고 생각해보자 

두 변수는 값이 아닌 하나의 주소를 공유한다. 원시값과 달리 주소를 따라가 보면 둘다 같은 메모리 주소가 

나오게 되므로 둘 중 하나가 값을 변경하면 다른쪽 변수 역시 값이 달라지게 된다. 

'진행중 > 모던 JS - 1회독 공부기록' 카테고리의 다른 글

공부기록 - 프로퍼티 어트리뷰트  (0) 2022.08.23
공부 기록 - 함수  (0) 2022.08.22
공부기록 - 객체  (0) 2022.08.20
공부기록 - 변환과 단축 평가  (0) 2022.08.20
공부기록 - 제어문  (0) 2022.08.20

자바스크립트는 원시값과 객체로 나뉘는데 자바스크립트는 객체 언어인 만큼 대부분이 객체임

원시값은 값이 변경이 안되지만 객체는 여러개를 둘수 있고 바꿀 수 있음

 

자바스크립트는 프로트타입 기반 객체언어로 객체 생성 방법이 다양함 

 

대표적으로 객체 리터럴인데 변수 선언하듯이 선언하고 {}를 붙이면 된다.

객체의 구성은 프로퍼티로 키와 값으로 구성된다 키 : 값

객체 안이 비어있어도 에러는 안남, 객체는 값은 모두 프로퍼티로 삼을 수 있음

객체의{}는 코드블록이 아님 그래서 세미클론 붙여야함 

프로퍼티에 키를 넣을 때 이름을 식별자 명명규칙을 따른다면 문자에 ''를 쓸 필요 없음

따르지 않는다면 ''를 꼭 붙여야 함 아니면 에러난다. 그리고 키와 값에 숫자형을 넣을 수 있음

다만 객체에 들어가면 문자형으로 바뀌는 걸 주의해야함 

마지막으로 중복선언해도 에러는 안나고 마지막 선언으로 값이 바뀌므로 주의가 필요함

 

메서드  -객체의 키의 값에 들어간 함수 일반 함수랑 구별하기 위해 메서드라 부른다.

객체 접근법- 마침표와 대괄호표기법이 있다. 마침표는 객체이름.키 로 구성된다.

대괄호는 객체이름.['키'] 로 구성된다. 키가 식별자 명명법에 따르지 않은 경우 마침표법은 불가능하고

무조건 대괄호 접근법을 이용해야 한다.  단, 키가 숫자형으로 이루어져 있다면 생략 가능하다. 

 

프로퍼티 값 갱신과 동적 생성

 

객체이름.키 = 값 을 사용하면 값을 갱신할 수 있다. 만약 키가 없다면 객체 안에 프로퍼티 생성까지 가능하다.

 

프로퍼티 삭제

 

deleate 연산자를 사용한다. deleate 객체.키 

삭제할 객체가 없어도 에러는 나지 않는다. 

 

프로퍼티 축약 표현

 

var x = 1; , y = 2;

var obj { 

x: x

y: y

}

키의 값에 변수에 할당된 값이 들어간다.

 

var x = 1; , y = 2;

var obj { 

x

y

}

 

x, y가 키 1, 2가 값이 된다. 

 

 

 

명시적 타입변환

 

var x = 10;

var str = x.toString();

console.log(typeof str, str);
 

암묵적 타입변환

var x = 10;
var str = x + '20'; //문자열로 변환
var num = x * '20';  //숫자형으로 변환

console.log(typeof str, str);
console.log(typeof num, num);
 
숫자타입 변환 
 
1 - '1' // 0
 
1 * '10' // 10
1 / 'one' // NaN
 
 
피연산자만 문자열로 바뀌는 것이 아니라 템플릿 리터럴의 삽입 역시 문맥에 맞게
암문적 타입 변환이 수행된다. 
 
var str =`1 + 1 = ${1 + 1}`; // "1 + 1 = 2"
 
 
'1' > 0 // true
 
비교 연산자의 역할은 불리언 값을 만드는 것으로 피연산자는 코드 문맥상 숫자타입이어야 한다.
비교를 위해 피연사자는 숫자타입으로 암묵적 타입 변환시킨다.
 
true를 반환하는 Truthy 값
 
'0' // 빈 문자열이 아니면 문자열은 참이다.
{}
[]
 
false를 반환하는 Falsy 값
 
false
undefined
null
0, -0
NaN
''(빈 문자열)
 
명시적 타입 변환
 
문자열로 변환 시키기
 
String();
().toString();
 
숫자 타입으로 변환
 
Number();
parseInt(); //문자열만 가능
parseFloat();
 
+'0';   //단항 산술 연산자 이용하는 방법
+'-1';
+'10.53';
+true;
+false

불리언 타입으로 변환

 

Boolean();

Boolean(NaN); false

Boolean({}); true

Boolean([]); true

 

 

단축평가

 

논리연산자를 사용한 단축평가

 

'Cat' && 'Dog' // -> Dog

 

빈 문자열만 아니면 문자열은 true로 둘다 true다. 논리곱 연산자는 좌항, 우항을 둘다 평가해야 값을 평가할 수 있으므로

먼저 'Cat'이 true임을 확인하고 우항인 'Dog'를 확인하고 그대로 'Dog'를 반환한다.

 

'Cat' || 'Dog' // -> Cat

 

논리합 연산자는 좌항만 ture만 나와도 우항을 평가할 필요가 없다.

이때 논리합 연산자는 문자열 'Cat'을 그대로 반환한다.

 

논리곱, 논리합 연산자는 논리연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 그대로 반환한다.

이를 단축평가라고 한다. 단축평가는 평가결과가 확정된 경우 나머지 평가를 생략하는 것을 말한다.

 

'Cat' || 'Dog' // 'Cat'

false || 'Dog' // 'Dog'

 

논리연산자 단축평가는 객체 프로퍼티 null, undefined 검사 역할을 할 수도 있다.

 

var elem = null;

var value = elem && elem.value; // null

 

옵셔널 체이닝 연산자

 

옵셔널 체이닝 연산자인 ?.은 좌항의 피연산자가 undefined 또는 null이면 undefined를 반환하고 그 외에는 우항의 참조값을 반환한다.  var value = num?.value;

 

null 병합 연산자 

 

null 병합 연산자 ??는 피연산자가 null, undefine이면 우항을 반환하고 아니면 좌항을 반환한다.

주의점은 undefined, null을 제외한 Falsy값이라면 좌항을 반환한다는 것이다.

 

 

'진행중 > 모던 JS - 1회독 공부기록' 카테고리의 다른 글

공부기록 - 원시값과 객체의 비교  (0) 2022.08.20
공부기록 - 객체  (0) 2022.08.20
공부기록 - 제어문  (0) 2022.08.20
공부기록 - 데이터 타입  (0) 2022.08.19
공부기록 - 표현식과 문  (0) 2022.08.18

+ Recent posts