일급 객체(First Class Citizen) 

- Frist Class Object

- 자바 스크립트의 함수는 일급 객체이다. -> 함수를 다른 함수의 인자로 줄 수 있다.

- 함수형 프로그래밍에서 통용된다.

 

 

일급 객체의 4가지 조건

1) 익명의 리터럴으로 생성 가능

2) 객체가 변수나 자료 구조에 저장이 가능 -> 다른 객체의 프로퍼티로 사용이 가능하다.

3) 객체를 다른 함수의 인자로 전달이 가능 

4) 함수의 리턴 값으로 객체 사용 가능

 

 

함수의 기능 변경 방법

1. 기존 함수 수정

2. 기존 함수 + 기능 추가로 새로운 함수 생성

3. 함수를 추상화 시켜서 인자로 받은 후 사용한다. -> 확장성 생각하기

 

 

콜백 함수(Callback Function)

- 매개변수를 통해서 다른 함수의 내부로 전달되는 함수

- 고차함수와 결합이 된다.

- 콜백 함수를 받은 고차 함수는, 함수 내부에서 콜백 함수를 호출할 수 있다.

 

 

고차 함수(High Ordered function)

- 매개변수를 통해서 콜백 함수를 전달받는 함수

- 함수를 인자로 전달받거나 결과로 반환하는 함수

 

함수 호출(Call, Invoke)

- 자바 스크립트는 오버로딩 발생 X 

- 이름으로만 호출한다.

- arguments(유사 배열 객체)라는 내부 객체를 통해서 인자의 개수가 달라도 호출이 가능하다. 

- return 값이 없으면 undefined가 출력된다.


즉시 실행 함수 IIFE(Immediately Invoked Function Expression)

- 함수를 선언함과 동시에 호출한다.

- 함수와 호출이 분리되어 있는 것이 아니라 합쳐져 있다. -> 재사용 불가능

- 즉시 실행 함수는 재활용이 불가능하기 때문에, 주로 익명함수 사용

- 전역변수를 최소화 하기 위해서 사용한다.

ex. 사용 예시 

- 파일1에서 사용한 변수를 파일2에서 똑같은 변수로 사용하려면 에러가 발생할 수 있다. 

- 즉시 실행 함수를 사용하면, 각각 지역 변수로 사용할 수 있기 때문에 스코프 충돌이 일어나지 않는다.

 

전역 변수

- 애플리케이션 생명 주기와 같기 때문에 메모리 차지의 위험성이 있다.

- 가독성이 나빠진다.

- 메모리의 리소스를 너무 많이 소모한다. (실행이 끝나기 전까지 차지하고 있기 때문에 가비지 컬렉터로 제거 불가능)

- 전역변수로 사용하게 되면, 다른 파일들과 메모리 공간을 공유하기 때문에 변수 충돌의 위험성이 존재한다. 

- 즉시 실행 함수로 전역 변수의 사용을 줄일 수 있다.


중첩 함수(nested function)

- 함수안에 함수가 있는 것

- 중첩 함수를 가지고 있는 바깥 함수를 외부 함수(outer function)이라고 한다.

 

 

스코프 체인(Scope Chain)

- 해당 코드의 유효 범위(스코프) 안에 있는 변수를 정희하는 객체의 체인이다.

 

ex. inner 함수 내에 있는 y를 찾기 위해서 해당 범위인 inner 함수에서 y를 찾는다.

- y가 없기 때문에, 상위 스코프인 outer 함수에서 y를 찾는다.

- 없으면, global 스코프로 가서 y를 찾는다.

- 주의할 점 : global에 변수를 사용하면, 프로그램의 성능이 느려질 수 있다. 

 

스코프(Scope)

- 식별자가 유효한 범위

- block level scope : 자바스크립트에서는 모든 블록(if, for, while, try/catch)이 지역 스코프를 만든다.

- function level scope : var 키워드로 선언된 변수는 함수 코드 블록만 지역 스코프로 만든다.

- 자바 스크립트 엔진이 식별자를 판단할 때 어떤 메커니즘으로 판단하는지? -> 스코프 체인(Scope Chain)

- 동적 스코프(Dynamic Scope) : 어디에서 호출하냐에 따라 스코프가 바뀐다.

- 정적 스코프(Static Scope), 렉시컬 스코프(Lexical Scope) : 호출은 상관 없지만, 어디에서 정의되는지에 따라 스코프가 바뀐다. -> 거의 대부분 언어가 사용

자바스크립트 함수

- 함수도 객체이다.

- 자바스크립트는 함수를 기본으로 하는 언어이다.

 

 

함수란?(function)

- 일련의 과정을 수행하기 위해서 statement를 { } 중괄호를 이용해서 하나의 실행 단위로 만들어 놓은 것

- 반복적인 code -> 함수화 // 유지 보수 향상, 오류 발생을 낮춰준다.

 

 

함수의 정의(Definition)

- 호출(call, invoke)

- call : 실제로 함수를 호출하는 명령문을 참조한다.

- invoke : 함수를 호출/실행하기 위해서 호출문을 간접적으로 참조한다.

- 파라미터(parameter) : function add(x, y)

- 리턴값 : return x+y

- 인자(argument) : add(3,5

 

 

함수 리터럴(literal)

- 리터럴(literal) : 값을 표현하기 위한 약속

- 함수의 선언만 있으면 사용할 수 없기 때문에 변수에 할당해주어야 한다.

- 함수 이름은 식별자(identifier)

- 함수 이름은 함수 내부에서만 사용 가능하다. -> 외부로 노출 XX

- 기명함수(Named function) 이름이 있는 함수 ex. function add()

- 익명함수(Anonymous function) 이름이 없는 함수 ex. function()

- 익명함수는 리터럴로 변수에 저장할 때 사용한다.

 

 

익명 함수를 사용하는 이유

- 함수는 함수 이름을 내부에서만 사용 가능하기 때문에 함수 이름을 굳이 쓸 필요가 없다.


함수 정의 방법

 

1. 함수 선언문

- function 키워드 사용

- 자바스크립트 엔진은 함수 이름을 암묵적으로 식별자 생성

 

2. 함수 표현식

- 함수 리터럴 사용

- 함수는 일급객체(함수를 값처럼 자유롭게 사용)여서 리터럴로 함수 객체를 변수에 할당할 수 있다.

- 함수 선언문은 실행 전에 함수 이름을 식별자에서 찾게 된다.

- 자바스크립트 엔진이 함수 선언문을 발견하게 되면, 함수 이름과 같은 변수를 만든다.

- 그래서 함수 밖에 있는 함수의 이름도 식별자로 호출할 수 있게 되어 실행이 가능해진다.

 

 

 

3. Function 생성자 함수 이용

- 사용하기 불편해서 권장 X

- 클로저(Closure)를 생성하지 않는다.

 

4. ES6 화살표 함수(Arrow function)

- 생성자 함수로 사용X

- prototype 프로퍼티가 없다.

- arguments 객체 생성X

기존 함수와 this 바인딩 방식이 다르다.

- 기존 함수에서 this는 자기 자신을 정의한다. 하지만 화살표 함수의 this는 상위 스코프의 this와 동일한 값ㅇ르 갖는다.

- 기존 함수를 사용하는 코드에서는 forEach 구문 안에 function() 선언문을 사용한다.

- relationship1과 서로 다른 함수 스코프를 가지게 되기 때문에 relastionship1을 가리키는 this를 따로 변수에 저장한다. 

var relationship1 = {
    name: 'kim',
    friends: ['a', 'b', 'c'],
    logFriends: function() {
        var that = this; // relationship1을 가리키는 this를 that에 저장
 
        this.friends.forEach(function(friend){
            console.log(that.name, friend);
        });
    },
};
relationship1.logFriends();

- 화살표 함수에서는 forEach문에서 function을 선언하지 않았기 떄문에, 바깥 스코프인 logFreinds()의 this를 그대로 사용 가능하다.

const relationship2 = {
    name: 'kim',
    friends: ['a', 'b', 'c'],
    logFriends() {
        this.friends.forEach(friend => {
            console.log(this.name, friend);
        });
    },
};
relationship2.logFriends();

 

함수 정의에 따라 constructor 유무

// 함수 선언문
function foo(){}

// 함수 표현식
var bar = function(){};

// 객체의 property로 함수가 할당
const barx = {
    x: function() {}
}

new foo(); // foo 함수 객체가 내부 메소드, // [[constructor]]를 가지고 있다.
new bar(); // [[constructor]]를 가지고 있다.
new barx.x(); // [[constructor]]를 가지고 있다.

const arrow = () => {}; 
//new arrow(); // error : arrow is not a constructor -> [[constructor]] 를 가지고 있지 않다.

const obj = {
    x() {
    }
    // [[constructor]] 를 가지고 있지 않다.
}
new obj.x()

함수 선언문 vs 함수 표현식

- 호이스팅 방식이 달라진다.

- 선언문은 런타임 이전, 표현식은 런타임 이후

- 함수 선언문 위에 함수를 호출하면 호출이 되지만, 표현식은 호출 불가능

 

 

함수 호이스팅(function hoisting)

- 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트의 특징

 

 

함수 선언문 호이스팅

 

ex.

function foo(){

    console.log('foo 함수');

};

- 실행하면, 스크립트 엔진이 foo 라는 식별자를 먼저 찾는다.

- 함수 선언문을 함수 이름과 같은 변수 foo를 묵시적으로 만들어준다.

 

- 함수 선언문에 대한 객체를 만들어서, 특정 메모리 공간에 넣어준다.

- primitive는 새로운 메모리 공간에다가 선언해주어야 한다. 

- 원래 값은 가비지컬렉션(GC)

 

 

함수 표현식 호이스팅

 

원시 값(Primitive value) vs 객체(Object)

- 원시 값은 값이 공유되지만, 객체는 reference가 복사된다.

- 결과적으로 같은 객체 지칭

  원시 타입(Primitive type) 객체 타입(Object)
immutable  mutable
할당 실제 값 저장 참조 값 저장
재할당 원시 값 복사 참조 값 복사
전달 방식 pass by value pass by reference

 

원시 타입

- 원시 값은 변경이 불가능하다.

- 원시 값을 재할당하기 위해서는 새로운 메모리 공간에서 재할당 값을 저장하고, 참조 변수의 메모리 공간 주소를 변경해야한다.

 

 

객체 타입

- 참조 값(reference value)에 접근할 수 있는 메모리 주소를 기억할 수 있다.

ex. var obj = {name: '홍길동'}

- 객체 리터럴을 통해(객체 생성 방법 중 하나) 객체가 생성된다.

- 원시 값을 할당한 변수 obj를 참조하면, 메모리 주소 0x23에 저장되어 있는 값에 접근한다.

- 메모리에 저장되어 있는 참조 값 0x99를 통해서 실제 객체 {name: '홍길동'}에 접근할 수 있다.

 

 

유사 배열 객체(Array Like Object)

- 배열처럼 index로 프로퍼티 값에 접근이 가능하고, length 프로퍼티를 갖는 객체이다.

- 배열처럼 index로 문자에 접근이 가능하다.

 

ex. primitive value인 'hello'는 래퍼 객체(wrapper Object)에 의해 자동 변환되어 객체로 변환해준다.

- 작업이 끝나면 다시 원시 값으로 되돌아온다.

- 문자열은 원시 값이기 때문에 변하지 않는다.

 

 

ex. let myStr = '홍길동';

- 객체가 만들어지고, myStr이 할당된다. 

- 그리고, length가 정해지고

- 배열처럼 사용할 수 있도록 0,1,2에 각각 키 값들이 만들어지고 각각 할당된다.

- 밑에도 여러가지 값들이 상속 되어 들어오게 된다. 

- myStr[0] 을 실행하면 0:홍을 가져와서 홍이 출력된다.

- 객체를 복사하면, 생성하는 비용을 절약할 수 있다.

- 하지만 이런 장점이 여러 개의 식별자가 하나의 객체를 공유할 수 있다는 단점이 존재한다.

 

 

값에 의한 전달(pass by value)

- 할당받는 변수에는 변수의 원시 값이 복사되어 전달된다. 

- scode변수와 copy의 값 80은 서로 다른 메모리 공간에 저장된 별개의 값이다.

 

 

참조에 의한 전달

let person = {name: 'Lee'}

let copy = person; 

- 객체를 가리키는 person을 다른 변수 copy에 할당하면, 원본의 참조 값이 복사된다.

- 두 개의 변수가 동일한 객체의 주소를 갖는다.

- 두 변수는 지정된 메모리 주소는 다르지만, 동일한 참조 값을 갖는다.

- 한쪽에서 값이 변경되면 다른쪽도 영향을 받는다.

- 자바스크립트에서는 '참조에 의한 전달'은 존재하지 않고, '값에 의한 전달'만 존재한다고 말할 수도 있다.

 

얕은복사 Shallow copy, 깊은 복사 Deep Copy

- 얕은 복사 : 객체의 한 단계만 복사

- 깊은 복사 : 객체에 중첩되어 있는 모든 객체 복사

 

 

옵저버(Observer) 패턴

- 객체의 변경은 복잡한 코드에서 객체의 변경 추적을 어렵게 한다.

- 객체의 변경을 추적하기 위해 옵저버 패턴을 사용하여 객체를 참조하는 모든 이들에게 변경 사실을 알리고 대처하는 추가 대응이 필요하다.

 

 

순수 함수

- 외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 함수

- 함수형 프로그래밍 : 순수 함수를 통해 프로그램의 안전성을 높이는 프로그래밍 패러다임 

객체(Object)

- 자바스크립트의 기본 타입(Data type)은 객체(Object)이다.

- 객체는 key와 value가 한 쌍으로 구성된 프로퍼티(Property)가 0개 이상인 정렬되지 않은 집합이다.

- 프로퍼티의 값으로 함수가 올 수도 있다 -> 이런 프로퍼티를 메소드(method)라고 부른다.(실제 메소드X)

- 숫자, 문자열, 불리언, undefiend 타입을 제외한 모든 것이 객체

- Primitive(숫자, 문자열, 불리언) 타입은 값이 정해진 객체로 취급되어, 객체로서의 특징도 가지게 된다.

- JSON 객체를 표현하기 위한 표준 중 하나이다.

- Property Key, Property Value

- 인스턴스(Instance) : 객체가 메모리에 저장되어 실제로 존재하는 것

name, age라는 property key를 가지고 있는 person 객체

 

 

프로퍼티(Property)

- key와 value으로 구성된 집합

 

(1) 프로퍼티 키(Property Key)

- 프로퍼티 값에 접근할 수 있는 이름

- 식별자 역할

- 식별자 네이밍 규칙을 따르지 않아도 되지만, 그렇게 되면 따옴표를 사용해주어야 하기 때문에 따르는 것이 좋다.

- 문자열, Symbol

ex. {'let': '문자열이지만, 권장되지 않는 키 네임'}

ex. let obj = {name: 'hong', name: 'kim'} -> console.log(obj)에서 kim 출력

ex. let obj = {name: 'hong'} -> console.log(obj.address) 찾는 key가 없기 때문에 undefined 출력

 

(2) 프로퍼티 값(Property Value)

- 자바 스크립트에서 value으로 인식되는 모든 것이 다 가능하다. 

- 문자열, 숫자, 함수(function)

- 함수도 가능하다.(메소드라고 부르긴 하는데 실제 메소드는 X) 

 

 

프로퍼티 동적 추가

- 점 표기법(Dot Notation) ->

- 괄호 표기법(Bracket Notation) -> []

 

프로퍼티 동적 삭제

- delete keyword

 

프로퍼티 접근

- 대괄호 프로퍼티 접근 연산자를 사용 할 경우, 프로퍼티 키를 반드시 따옴표로 감싸주어야 한다.

- 감싸지 않는 경우, 자바스크립트 엔진이 프로퍼티 키를 식별자로 해석하기 때문


객체 생성 방법

 

1. 객체 리터럴 (Object Literal)

- 가장 간단한 방법 {} 사용

- 단점은 똑같은 객체를 여러 개 만들어야 한다. 

- 변수가 할당되는 시점에 엔진이 객체 리터럴을 해석해서 객체 생성

 

2. Object() 객체 생성자 함수

- 자바스크립트 내장 함수

- Object 객체는 자바스크립트의 최상위 객체이다.

- 자바스크립트의 모든 기본 내장 객체는 Object 객체를 기본으로 만들어진다.

 

3. 생성자 함수(User Defined)

- 함수를 통해서 객체를 생성하는 방식

- 객체를 만들 때마다 프로퍼티에 대한 공간이 메모리에 할당되어서 비효율적

- 일반 함수와 생성자 함수를 구분하기 위한 일반적 약속

- 일반 함수 : 첫글자(소문자)

- 생성자 함수 : 첫글자(대문자)

 

4. Object.create() method

5. ES6 -> class

 


객체 리터럴 확장 방식

- ES6에서 추가

 

User Define(사용자 정의) 생성자 함수로 객체 생성

const person1 = Person();
console.log(person1); // undefined

const person2 = new Person(); // new를 붙여서 생성자 함수로 호출 -> 내부적으로 Instance를 만든다
console.log(person2); // Person {}

const person3 = {}; // 일반 객체
console.log(person3); // {} 

// new 생성자 함수로 호출
// 내부적으로 Instance를 만들어준다.
// 안에 아무거나 없으면
// this를 바인딩해서 this를 리턴해준다.

 

 

var const let 차이

  var const let
범위 Function Scope Block Scope
값 재정의 O X O
재선언 O X X

 

var

- 중복 선언이 가능하다.

- var는 function scope 생성


let, const

- ES6에 도입

- const는 재할당 불가능

1) 중복 선언이 되지 않는다.

 

2) Block level Scope

- 블록 안에서만 사용 가능하다.

 

3) let을 이용하면 호이스팅이 되지 않는 것 처럼 동작한다.

 

4) let으로 변수를 선언하면 변수를 일시적으로 사용할 수 없는 구간인 일시적 데드존 TDZ(Temporal Dead Zone)이 생긴다.

 


Primitive Value의 불변한(immutable) 특성

- var scope를 선언하고, scope에 80을 할당하면 아래 그림과 같이 생각할 수 있다.

- 하지만 primitive value는 불변의 특성을 가지고 있기 때문에, 값이 바뀌는 것이 아니라 주소 값이 바뀐다.

- 그리고 원래 사용되지 않는 주소 값들은 가비지컬렉터를 사용해서 메모리를 할당 해제(가비지 컬렉션 GC)한다.

 

템플릿 문자열

- 백틱(`)을 사용해서 새로운 문자열 생성 가능

var string = num1 + ' + ' + num2 + ' = ' + result;

const string = `${num1} + ${num2} = ${result}`;

메모리(Memory)

- 데이터를 저장할 수 있는 메모리 셀(Memory Cell)의 집합체

 

 

변수(Variable)

- 애플리케이션서 값에 상징적인 이름으로 변수를 사용한다.

- 변수명 = 식별자

 

 

식별자(Identifier)

- 코드 내의 변수, 함수 혹은 속성을 식별하는 문자열

- 식별자가 실제로 갖고 있는 값은 메모리 값이다.

- Naming rule : $, - 사용 가능, 숫자 시작 불가능, 특수 문자 불가능

- CPU(Central Processing Unit) 중앙 처리 장치 : 연산에 사용

- memory 주소를 알아야 variable을 이용해서 해당 메모리 사용 가능

- 메모리에 대한 직접 접근을 막고있기 때문에 변수 선언을 해주어야 한다.

 

 

변수 생성 방법 

- ES6 이전

- function level scope 함수 기준 스코프

(1) var 

 

- ES6 이후

- block level scope 블록 기준 스코프

(1) let

(2) const

 

 

ex. var score;

scope = 80;

scope = 100;

 

실행 컨텍스트(Execution Context)

- 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념

- 코드를 실행하기 위해서는 해당 코드에 대한 정보를 가지고 있어야 한다.

 

ex. score가 0x2763을 가르킨다는 것은 어떻게 알 수 있는지??

-> 실행 컨텍스트가 정보를 가지고 있다.

 

- 전역 컨텍스트(Global Context)

- 함수 컨텍스트(Functional Context)

 

 

undefined

- primitive value(원시 값)중 하나

- JS Engine에 의해 사용된다.

- 개발자가 직접 사용하는 것은 지양한다.

- 변수를 초기화할 때 사용한다.

 

 

변수 호이스팅(Variable hoisting)

- 함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위(Scope)의 최상단에 선언하는 것

- 자바 스크립트의 특징

- var 변수 선언과 함수 선언문에만 호이스팅이 일어난다. (function scope)

- 자바 스크립트는 식별자를 먼저 확인한다.

- 변수 선언을 runtime 이전에 수행하고, 함수 위로 끌어올려준다.

- 자바 스크립트에 나오는 모든 식별자들은 호이스팅된다.

function getX() {
  console.log(x); // undefined
  var x = 100; // var x 호이스트
  console.log(x); // 100
}
getX();


foo( );
var foo = function( ) {
  console.log(‘hello’);
};
// type error
  • 1. 함수 선언문은 항상 자바스크립트 엔진 구동시 가장 최우선으로 해석되어 호이스팅된다.
    • 함수 선언을 호이스팅해서 global 객체에 등록시키기 때문에 출력
  • 2. 함수 표현식은 런타임 과정에서 이루어지기 때문에 호이스팅 X
    • 함수 리터럴을 할당하기 때문에 런타임 환경에서 type error

타입스크립트(TypeScript)
- 2012년 MS에서 구현한 JavaScript의 슈퍼셋(Superset) 프로그래밍 언어 // ECMAScript의 super.set

- 클래스 기반 객체지향언어

- 확장자 .ts

- 컴파일의 결과물로 JavaScript 코드 출력이라고 할 수 있지만, 컴파일은 "기계어로 번역하는 과정"을 뜻한다.

- TypeScript -> Compile(X) Transpile(변환) -> JavaScript

- JavaScript에는 추상 클래스가 없다. TypeScript를 가지고 추상 클래스로 구현하면 JavaScript에서 같은 기능을 내줄 수 있다.

- NPM이 필요하다. -> Node.js 설치 필요

 

 

타입스크립트의 장점

- 정적 타입을 명시할 수 있다.

- 생산성 향상 : 자바스크립트에 비해 변수나 함수 등의 목적을 더욱 명확하게 전달할 수 있다.

 

 

Node.js

- 오픈소스 JavaScript 엔진인 크롬 V8에 비동기 이벤트 처리 라이브러리인 libuv를 결합한 플랫폼

- Javascript으로 브라우저 밖에서 서버를 구축하는 등의 코드를 실행할 수 있게 해주는 런타임 환경

- NPM을 통해서 Node.js의 패키지를 관리할 수 있다.

- Transpiler : TypeScript

- 자동화 도구 : Build, Test, Deploy를 자동화 -> gulp

- 모듈화 : webpack

- 프레임워크 : Angular, React, Vue.js

- V8 엔진 사용(Chrome)

 

 

NPM(Node Package Manager)

- Node.js의 패키지를 관리해주는 도구

- Node.js 설치시 자동으로 설치된다.

- TypeScript를 사용할 때 필요하다.

+ Recent posts