object 생성자 함수

new 연산자와 함께 Object 생성자 함수를 호출하면 빈 객체를 생성하며 반환한다.

// 빈 객체 생성
const student = new Object();

//프로퍼티 추가
student.name = '유관순';
student.age = 16;

console.log(student);   // { name: '유관순', age: 16 }

 

생성자 함수에 의한 객체 생성
객체 리터럴을 이용한 객체 생성 방식은 직관적이고 간편하지만, 단 하나의 객체만 생성하므로
동일 프로퍼티를 갖는 객체를 여러 개 생성해야 하는 경우 매번 같은 프로퍼티를 기술하므로 비효율적이다.
const student = {
    name : '유관순',
    age : 16,
    getInfor () {
        reurn `${this.name}(은)는 ${this.age}세 입니다.`;
    }
};

const student2 = {
    name : '홍길동',
    age : 20,
    getInfor () {
        reurn `${this.name}(은)는 ${this.age}세 입니다.`;
    }
};

const student3 = {
    name : '선덕여왕',
    age : 30,
    getInfor () {
        reurn `${this.name}(은)는 ${this.age}세 입니다.`;
    }
};

 

- 객체를 생성하기 위한 템플릿처럼 생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러 개를 생성할 수 있다.
- 빈 객체 생성 이후 프로퍼티 또는 메서드를 추가하여 객체를 완성할 수 있다.
function Student(name, age) {
    // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
    this.name = name;
    this.age = age;
    this.getInfor = function () {
        return `${this.name}(은)는 ${this.age}세 입니다.`;
    }
}

// 인스턴스의 생성
const student4 = new Student('장보고', 35);
const student5 = new Student('신사임당', 40);

console.log(student4);   //Student { name: '장보고', age: 35, getInfor: [Function (anonymous)] }
console.log(student5);   //Student { name: '신사임당', age: 40, getInfor: [Function (anonymous)] }

 

인스턴스 생성 과정
function Student(name, age) {

    1. 암묵적으로 인스턴스가 생성되고 this에 바인딩되는 과정이 런타임 이전에 실행된다.
    console.log(this); // this = Student {}   =>  student 타입의 빈 객체
    
    2. this에 바인딩 되어 있는 인스턴스를 초기화 한다.
    this.name = name;
    this.age = age;
    this.getInfor = function () {
        return `${this.name}(은)는 ${this.age}세 입니다.`;
    }
    
    3. 완성된 인스턴스가 바인딩 된 this가 암묵적으로 반환된다.
       // Student {} 출력
        만약 명시적으로 객체를 반환하면 암묵적인 this 반환이 무시된다.
        return {};  // Student {} 가 아니라 {}가 반환됨
        하지만 명시적으로 원시값을 반환하면 this가 반환된다.
        return 1;   // Student {} 반환
       
        => 생성자 내부에서 return은 생략하는 것이 기본이다.
}

const student = new Student('홍길동', 20);
console.log(student);  

// 위의 각 경우의 출력값과 함께 
//Student { name: '홍길동', age: 20, getInfor: [Function (anonymous)] }

 

일반 함수와의 차이점 

일반 함수와 생성자 함수의 형식적인 차이는 없다.(첫 문자를 대문자로 기술하여 구별하고자 노력한다.)

단, new 연산자와 함께 호출될 때 생성자 함수로 동작하며 만약 new 연산자와 함께 호출되지 않으면 일반 함수로 동작한다.
function Student(name, age) {
    console.log(this);  //전역 객체 
    this.name = name;
    this.age = age;
    this.getInfor = function () {
        return `${this.name}(은)는 ${this.age}세 입니다.`;
    }
}

일반 함수로 호출된 Student는 반환문이 없으므로 undefined를 반환한다.

const student = Student('강감찬', 35);

console.log(student);    //undefined

 

일반 함수로 호출된 Student내의 this는 전역 객체를 가리킨다. 전역에서 쓸 수 있는 여러가지 기능이 담겨있다.

console.log(age);            //35
console.log(name);           //강감찬
console.log(getInfor());     //강감찬(은)는 35세 입니다.

 

new.target
  • 생성자 함수가 new 연산자 없이 호출되는 것을 방지하기 위해 ES6에서는 new.target을 지원한다.
  • new 연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target은 함수 자신을 가리킨다.
  • new 연산자 없이 일반 함수로 호출된 함수 내부의 new.target은 undefined이다.

 

function Dog(name, age) {

    if(!new.target) {  
        
        return new Dog(name, age); 
    }  
    
    this.name = name;
    this.age = age;

}

=> new 연산자와 함께 호출되지 않은 경우 undefined이므로 new 연산자와 함께 생성자 함수를 재귀 호출하여 생성된 인스턴스를 반환한다.

그 후엔 new 연산자 없이 호출해도 new.target을 통해 생성자 함수로서 호출 된다.

const dog = Dog('뽀삐', 3);
console.log(dog);
//Dog { name: '뽀삐', age: 3 }

 

 

대부분의 빌트인 생성자 함수(Object, String, Number, Boolean, Date, ...)는 new 연산자와 함께 호출되었는지 확인 후 적절한 값을 반환한다.
 
String, Number, Boolean의 경우 new 연산자 없이 호출하면 객체 값이 아닌 문자열 숫자, 불리언 값(원시 값)을 반환한다. 이를 데이터 타입 변환에 활용하는 것이다.

 

전역과 지역 스코프

  • 전역 스코프
전역은 코드의 가장 바깥 영역을 말하며 전역은 전역 스코프를 만든다.
전역에 변수를 선언하면 전역 스코프를 갖는 전역 변수가 되며 전역 변수는 어디서든 참조 가능하다.
 
  • 지역 스코프
지역이란 함수 내부 몸체를 말하며 지역은 지역 스코프를 만든다.
지역에 변수를 선언하면 지역 스코프를 갖는 지역 변수가 되며, 자신의 지역 스코프와 하위 지역 스코프에서 유효하다.

 

var x = 'global x';
var y = 'global y';

function outer () {
    var z = "outer's local z";

    console.log(x);     // global x
    console.log(y);     // global y
    console.log(z);     // outer's local z

    function inner () {
        var x = "inner's local x";

        console.log(x);     // inner's local x
        console.log(y);     // global y
        console.log(z);     // outer's local z
    }

    inner();

}

outer();

console.log(x);     // global x
console.log(y);     // global y
console.log(z);     // ReferenceError: z is not defined 전역에는 z가 없다
  • 스코프 체인
 
전역 스코프 (x, y, outer) <- outer 지역 스코프 (z, inner) <- inner 지역 스코프 (x)
 
자바스크립트 엔진은 변수를 참조할 때 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여
상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
 
=> 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조 가능,
      하위 스코프에서 유효한 변수는 상위 스코프에서 참조 불가능

 

함수 레벨 스코프

- C, Java 등 대부분의 프로그래밍 언어는 함수 몸체만이 아니라 모든 코드 블록(if, for, while, try/catch 등)이
지역 스코프를 만드는 "블록 레벨 스코프"를 가진다.
-> 블록 안에 선언된 변수를 바깥에서 사용할 수 없다.
`
- 하지만 var 키워드로 선언 된 변수는 오로지 함수의 코드 블록(함수의 몸체)만을 지역 스코프로 인정하는 "함수 레벨 스코프"를 가진다.
- ES6에서 도입된 let, const 키워드는 블록 레벨 스코프를 지원한다.
// i는 전역 변수
var i = 0;

// 전역 변수로 이미 선언 된 i가 중복 선언 된다.
for(var i = 0; i < 10; i++) {}

// for 코드 블럭 내부의 값 변화가 반영된다. 
console.log(i);
 

 

var

ES5까지 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었는데 이는 몇가지 문제를 유발한다.

1. 변수 중복 선언

- var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언이 허용된다.

- 초기화 문이 있는 변수 선언문은 자바스크립트 엔진에 의해 var 키워드가 없는 것처럼 행동한다.

- 초기화 문이 없는 변수 선언문은 무시된다.

var msg = "안녕하세요";
console.log(msg);          // 안녕하세요

var msg = "안녕히가세요";
console.log(msg);          // 안녕히가세요

var msg;
console.log(msg);		   // 안녕히가세요

 

2. 함수 레벨 스코프

 

3. 변수 호이스팅

- 변수 선언문이 스코프의 선두로 끌어올려진 것처럼 동작하여 변수 선언문 이전에 참조할 수 있다.

console.log(test);  	//undefined
test = "반갑습니다";
console.log(test); 	    //반갑습니다
var test;

 

let

var 키워드의 단점을 보완하기 위해 ES6에서는 새로운 변수 선언 키워드인 let, const를 도입했다.

1. 변수 중복 선언 금지

- 같은 스코프 내에서 중복 선언을 허용하지 않는다.

let msg = "안녕하세요";

let msg = "안녕히가세요";  -> 블록 범위 변수 'msg'을(를) 다시 선언할 수 없습니다.

2. 블록 레벨 스코프

- 모든 코드 블록을 지역 스코프로 인정한다.

let i = 0;
for(let i = 0; i < 10; i++) {
    console.log(`지역 변수 i : ${i}`);    // 0~10 출력
}
console.log(`전역 변수 i : " ${i}`);	  // 전역 변수 i : 0

 

3. 변수 호이스팅

- 변수 호이스팅이 발생하지 않은 것처럼 동작한다.

console.log(x); //ReferenceError: Cannot access 'x' before initialization
let x;

* var : 선언, 초기화 동시   /    let : 선언, 초기화 분리되어 동작

 

const

let 키워드에서 알아본 특징은 모두 동일하며, 상수(const) 선언에서만 사용된다는 점이 특징이다.

- const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다.

- const 키워드로 선언한 변수는 재할당 금지

const x;          // 'const' 선언은 초기화해야 합니다.

const x = 1;

x = 2; 			 // TypeError: Assignment to constant variable.

- 일반적으로 상수의 이름은 대문자로 선언해 상수임을 나타내며, 여러 단어로 이루어진 경우 _(언더스코어)로 구분해서 스네이크 케이스로 표현하는 것이 일반적이다.

const DISCOUNT_RATE = 0.15;

- const 키워드로 선언된 변수에 객체를 할당할 경우 프로퍼티 값을 변경할 수 있다.

- 객체 재할당은 불가능하다.

const student = {
    name : '홍길동',
    age : 20
};



student.name = '유관순';
console.log(student);        // { name: '유관순', age: 20 }



student = {};                // TypeError: Assignment to constant variable.

 

화살표 함수 기본 문법

ES6에서 도입 된 화살표 함수는 function 키워드 대신 화살표를 사용해 보다 간략하게 함수를 선언하는 방법이다.
 
  • 화살표 함수는 항상 익명함수로 정의하며 본문이 한 줄인 함수를 작성할 때 유용하다.
var message;

// 기존 function 정의
message = function() {
    return 'hello world!';
};

console.log(message());               //hello world!

// function 키워드 생략
message = () => {
return 'Arrow Function!';
};

console.log(message());              //Arrow Function!
-명령문이 하나만 있을 경우 중괄호 생략 가능
 
-함수 몸체 내부의 문이 값으로 평가 될 수 있는 표현식인 문이라면 암묵적으로 반환(return 생략 가능)
message = () => 'Arrow Functions are simple!';

 

  • 매개 변수가 있을 경우
message = (val1, val2) => 'Arrow ' + val1 + val2;

console.log(message('Function', '!'));

//Arrow Function!

 

  • 매개변수가 하나이면 소괄호를 생략
매개변수가 없거나 여러 개일 경우 생략 불가
message = val1 => "Arrow " + val;
console.log(message('Functions are GOOD!!!'));


//Arrow Functions are GOOD!!!

 

즉시 실행 함수

함수 정의와 동시와 즉시 호출이 되는 함수로 단 한번만 호출 되며 다시 호출할 수 없다.
즉시 실행 함수는 반드시 () - 그룹 연산자로 감싸야 한다.
 
  • 함수 이름이 없는 익명 함수를 사용하는 것이 일반적이다.
(function() {
	console.log('익명 즉시 실행함수! 함수 정의와 동시에 호출!' )
 })();
  • 이름을 지어도 다시 호출할 수 없기에 의미가 없다.
(function hello(name){  -> 매개변수
	console.log('기명 즉시 실행함수! 함수 정의와 동시에 호출!');
    console.log(`${name}님 안녕하세요`);
})('홍길동');  -> 전달값


hello('유관순');   // ReferenceError: hello is not defined




//출력
기명 즉시 실행함수! 함수 정의와 동시에 호출!
홍길동님 안녕하세요

 

즉시 실행 함수 용도
 
: 즉시 실행 함수 내에 코드를 모아두면 밖에 있는 코드들과 영역을 분리하여 혹시 있을수도 있는 변수나 함수의 이름 충돌을 방지할 수 있다.

 

재귀 함수

함수가 자기 자신을 호출하는 것을 재귀 호출이라고 한다.
이러한 재귀 호출을 수행하는 함수인 재귀 함수는 반복되는 처리를 위해 사용한다.
 
 
- 팩토리얼(n! = 1 * 2 * ... * (n-1) * n;)을 재귀함수로 표현할 경우
function factorial(n) {
	
    //n이 1 이하일 때 1을 반환하여 반복을 멈춤
    if(n <= 1) return 1;
    
	return n * factorial(n-1);  //재귀 호출

}
 

-> 재귀 함수로 표현하는 것이 직관적인 경우 사용, 잘못 사용하면 스택오버플로우 현상이 발생할 수 있으므로 남용X

 

중첩 함수

함수 내부에 정의 된 함수를 중첩 함수 또는 내부 함수라고 한다.
 
- 중첩 함수를 포함하는 함수는 외부 함수라고 한다.
- 외부 함수의 변수를 내부 함수에서 참조할 수 있다.
- 일반적으로 중첩 함수는 자신을 포함하는 외부 함수를 돕는 헬퍼 함수의 역할을 한다.
 
function outer () {
    var outerVal = '외부 함수';

    function inner () {
        var innerVal = '내부 함수';
        console.log(outerVal + ", " + innerVal); 
    }

    inner();  //내부 함수를 호출해야 내부 함수의 동작을 가져다 쓴다. 출력 가능

}

outer();  // 출력불가. outer 함수 선언만 읽혀진다.
inner();  // outer 안에서 동작하는 함수이기 때문에 인식 안됨.


// 출력
외부 함수, 내부 함수

 

콜백 함수

함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라고 한다.
- 매개변수를 통해 함수의 외부에서 콜백 함수를 전달 받은 함수를 고차 함수라고 한다.
- 콜백 함수는 고차 함수에 전달 되어 헬퍼 함수의 역할을 한다.
// 전달 받는 값을 증가 시켜주는 함수
function increase(value) {
    return value + 1;
}

// 전달 받는 값을 감소 시켜주는 함수
function decrease(value) {
    return value - 1;
}
 
 - 고차 함수는 매개변수를 통해 전달 받은 콜백 함수의 호출 시점을 결정해서 호출한다.
 - 콜백 함수는 고차 함수에 의해 호출 되며 이 때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
 
 
// 전달 받은 함수에 전달 받은 값을 적용 시켜주는 고차 함수
function apply(func, value) {
  
    return func(value);
}

// 고차 함수로 콜백 함수를 전달하며 호출한다.

console.log(apply(increase, 5));   // 6
console.log(apply(decrease, 5));   // 4

 

- 콜백 함수가 고차 함수 내부에서만 호출 된다면 콜백 함수를 익명 함수 리터럴로 정의하면서 바로 고차 함수에 전달하는 것이 일반적이다.

 

console.log(apply(function(value){ return value + 1;}, 10));   // 11  -> 함수명 생략
console.log(apply(value => value -1, 10));       // 9  -> function 생략, 중괄호, 리턴 생략

 

- 함수의 변하지 않는 공통 로직은 미리 정의해두고 경우에 따라 변경 되는 로직은 추상화해서 함수의 외부에서 내부로 전달하는 방식이다.
- 콜백 함수는 비동기 처리(이벤트, 타이머, ajax)에서 활용 되는 중요한 패턴이며 배열 고차 함수에서도 사용 된다.

 

* 참고

배열은 대괄호[]

sort() 함수는 배열을 정렬하는 함수. 정렬 기준을 전달 받는다.sort() 함수는 고차 함수, 정렬기준 함수는 콜백 함수이다.

console.log([3, 1, 4, 2, 5].sort((left, right) => right - left));


-> 양수가 반환되면 순서를 바꾼다. 역순으로 정렬됨 [5, 4, 3, 2, 1]

 

순수함수와 비순수함수

순수 함수 : 외부 상태에 의존하지도 않고 변경하지도 않는 함수
비순수 함수 : 외부 상태에 의존하거나 외부 상태를 변경하는 함수
 
-> 함수 외부 상태의 변경을 지양하는 순수 함수를 사용하는 것이 좋다.

 

- 순수 함수는 최소 하나 이상의 인수를 전달 받으며 인수의 불변성을 유지한다.

var cnt = 0;

function increase(n) {
    return ++n;
}

- 순수 함수가 반환한 결과 값을 변수에 재할당해서 상태를 변경한다.

cnt = increase(cnt);
console.log(cnt);     // cnt 는 1이 출력된다

 

- 비순수 함수는 외부 상태에 의존하며 외부 상태를 변경한다.

function decrease() {
    return --cnt;
}

 

- 비순수 함수는 외부 상태(cnt)를 변경하므로 상태 변화를 추적하기 어려워진다.

-> 함수는 input을 받아서 연산한 값을 반환하는 형태가 좋다.

decrease();        // --cnt로 변경
console.log(cnt);  // 0

 

함수 선언문

function hello(name) {
    return `${name}님 안녕하세요.`;
}

함수 호출

console.log(hello('홍길동'));
// 홍길동님 안녕하세요.

 

함수 표현식

자바스크립트의 함수는 객체 타입의 값으로 값의 성질을 갖는 일급 객체이다.(밑에 설명)

함수 리터럴로 생성한 함수 객체를 변수에 할당할 수 있다.

  • 함수 표현식에서는 함수명을 생략할 수 있다.
var hello = function (name) {
    return `${name}님 안녕하세요`;
}

console.log(hello('홍길동'));
// 홍길동님 안녕하세요
  • 함수 표현식에서 함수명을 생략하지 않아도 문제는 없다.
var calc = function add(a,b) {
    return a + b;
}
  • 단, 함수 호출은 식별자로 이루어지며 함수명으로 호출할 수 없다.
console.log(calc(10, 20));
//console.log(add(10,20));

 

함수 호이스팅

함수 선언문은 런타임 이전 자비스크립트 엔젠에 의해 먼저 실행된다. 따라서 함수 선언문 이전에 함수를 참조할 수 있고 호출할 수 있다. 

함수 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는 것을 '함수 호이스팅'이라고 한다.

console.log(hello('홍길동'));
console.log(hi('홍길동'));      //TypeError: hi is not a function

//함수 선언문
function hello(name) {
    return `${name}님 안녕하세요!`;
}

// 함수 표현식
var hi = function(name) {
    return `${name} 안녕!`;
}

변수 할당문의 값은 할당문이 시행되는 시점, 즉 런타임에 평가되므로 함수 표현식의 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다.

함수 표현식으로 정의한 함수는 반드시 함수 표현식 이후에 참조하고 호출해야 한다.


매개변수와 인수

  • 매개변수는 함수 몸체 내부에서만 참조할 수 있다.
  • 모든 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관된다.
    • 가변인자 함수 구현 시 유용하게 사용 된다.
function hello(name) {
	
    console.log(arguments);
    
    return `${name}님 안녕하세요`;
}


//console.log(name); -> 매개변수는 함수 몸체 외부에서 참조할 수 없다.

var result = hello('홍길동');
console.log(result);  

//  [Arguments] { '0': '홍길동' }
//  홍길동님 안녕하세요
 
 
 
  • 함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않는다.
    • 인수가 부족해서 할당 되지 않은 매개변수의 값은 undefined이다.
result = hello();
console.log(result);

// [Arguments] {}
// undefined님 안녕하세요
 
  •  매개변수보다 인수가 더 많은 경우 초과된 인수는 무시된다.
result = hello('유관순', '신사임당');
console.log(result);

// [Arguments] { '0': '유관순', '1': '신사임당' }
// 유관순님 안녕하세요
 
 
 
- 인수를 전달하지 않았을 경우, undefined를 전달하였을 경우 매개변수 기본값이 동작한다.(ES6에서 도입)
 
function hi(name = '아무개') {

    return `${name} 안녕~`;
}

result = hi('홍길동');
console.log(result);     //홍길동 안녕~
result = hi();
console.log(result);	 //아무개 안녕~

 

 
- 매개변수의 최대 개수에 대해 명시적인 제한은 없다.하지만 이상적인 함수는 한 가지 일만 해야 하며 가급적 작게 만들어야 하므로 최대 3개 이상을 넘지 않는 것을 권장함.

 

반환문

반환문은 리턴 키워드 뒤에 오는 값을 반환한다.
 
 
function hello(name) {
    // 반환문
    return `${name}님 안녕하세요!`;
    // 반환문 이후의 문은 실행되지 않고 무시 된다.
    console.log(name);
}



console.log(hello('유관순'));



-> 유관순님 안녕하세요!
 
 
 
 
- 반환 값을 명시적으로 지정하지 않으면 undefined가 반환된다.
 
function func() {
    console.log('함수가 호출 되었습니다.');
    //return; 
    // 반환 값이 없을 시 반환문 생략 가능하며 이 때도 암묵적으로 undefined 반환
}

console.log(func());




-> 함수가 호출 되었습니다.
   undefined
 
 

 


일급 객체 

1. 무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다.
2. 변수나 자료구조(객체, 배열 등)에 저장할 수 있다.
3. 함수의 매개변수에 전달할 수 있다.
4. 함수의 반환값으로 사용할 수 있다.
=> 값을 취급할 수 있다.
 

예시 (뒤에 함수 내용 숙지)

- 무명의 리터럴로 생성할 수 있다.

- 변수에 저장할 수 있다.
// 함수명이 없고 변수 hello에 저장됨
var hello = function () {
    return '안녕!';
};

- 객체에 저장할 수 있다.

var obj = { hello };     // hello : hello   hello라는 함수를 hello라는 속성으로 객체에 저장

 

- 함수의 매개변수에 전달할 수 있다.
- 함수의 반환값으로 사용할 수 있다.
function repeat(func, count) {          //매개변수
    for(var i = 0; i < count; i++) {
        console.log(func());
    }
    
    return function () {  // 반환값
        console.log(`${count}번 반복 완료`);
    }
}

var returnFunc = repeat(obj.hello, 5);
returnFunc();


실행 시
안녕!
안녕!
안녕!
안녕!
안녕!
5번 반복 완료
출력
 
- 함수가 일급 객체라는 것은 함수를 객체와 동일하게 사용할 수 있다는 의미이다.
 
객체는 "값"이므로 함수는 값과 동일하게 취급할 수 있다.
변수 할당문, 객체의 프로퍼티 값, 배열의 요소, 함수 호출의 인수, 함수 반환문 등에서 사용할 수 있다.
 

프로퍼티 값 단축 구문

ES6에서는 프로퍼티 값으로 변수를 사용하는 경우 변수 이름과 프로퍼티 키가 동일한 이름일 때 프로퍼티 키를 생략할 수 있다. 이 경우 프로피터 키는 변수 이름으로 자동 생성된다.

var id = 'p-00001';
var price = 30000;

var product = {
    id : id,
    price : price
};

var product2 = { id, price };

// product, product2 둘다 { id: 'p-00001', price: 30000 } 출력됨

 

계산된 프로퍼티 이름

ES5에서는 계산된 프로퍼티 이름으로 프로퍼티 키를 동적 생성하려면 객체 리터럴 외부에서 대괄호 표기법을 사용해야 한다. 

obj[key] = value;

var prefix = 'key';
var index = 0;
var obj = {};

obj[prefix + '-' + index++] = index;
obj[prefix + '-' + index++] = index;
obj[prefix + '-' + index++] = index;

console.log(obj);

// 출력 -> { 'key-0': 1, 'key-1': 2, 'key-2': 3 }

 

ES6에서는 객체 리터럴 내부에서도 계산되니 프로퍼티 이름으로 프로퍼티 키를 동적 생성할 수 있다.

var obj2 = {
    [`${prefix}-${index++}`] : index,
    [`${prefix}-${index++}`] : index,
    [`${prefix}-${index++}`] : index
};

console.log(obj2);

// 출력 -> { 'key-3': 4, 'key-4': 5, 'key-5': 6 }

 

메서드 단축

ES5에서 메서드를 정의하려면 프로퍼티 값으로 함수를 할당한다.

ar dog = {
    name : '뽀삐',
    // 메소드 : 객체 내부에 정의된 함수
    eat : function(food){
        console.log(`${this.name}(은)는 ${food}를 맛있게 먹어요.`);
    }
};

dog.eat('고구마');

// 뽀삐(은)는 고구마를 맛있게 먹어요.

 

ES6에서 메서드를 정의할 때 function 키워드를 생략한 축약 표현을 사용할 수 있다.

var dog2 = {
    name : '뽀삐',
    eat(food){
        console.log(`${this.name}(은)는 ${food}를 맛있게 먹어요.`);
    }
};

dog2.eat('고구마');

//뽀삐(은)는 고구마를 맛있게 먹어요.

 


in 연산자

in 연산자를 통해 프로퍼티 존재 여부를 확인할 수 있다.

프로퍼티 값이 undefined일 뿐 프로퍼티는 존재하는데, 존재하지 않는다고 판별될 수 있는 문제가 있다.

var student = {
    name : '유관순',
    age : 16,
    test : undefined
};

console.log(student.name === undefined);     // false - 존재
console.log(student.height === undefined);     // true - 존재하지 않음
console.log(student.test === undefined)     // true - 존재하지 않음

이럴 경우 in 연산자로 판단한다.    

console.log("name" in student);    //true
console.log("height" in student);  // false
console.log("test" in student);    // true

 

for in 반복문 

for in 반복문을 이용해 객체의 모든 키를 순회할 수 있다.

var student = {
    name : '유관순',
    age : 16,
    getInfo(){
        return `${this.name}(은)는 ${this.age}세 입니다.`;
    }
};


console.log(student);

// { name: '유관순', age: 16, getInfo: [Function: getInfo] }

 

- 반복할 때마다 프로퍼티 키 값을 준다.

for(var key in student) {  
    console.log(`key : ${key}`);                    //프로퍼티 키 값
    console.log(`student['${key}'] : ${student[key]}`);  //프로퍼티 키에 해당하는 value 값
}


// 출력
key : name
student['name'] : 유관순
key : age
student['age'] : 16
key : getInfo
student['getInfo'] : getInfo(){
        return `${this.name}(은)는 ${this.age}세 입니다.`;
    }

- value 값 호출할 때 student.key 형태는 안된다.

key : value 라는 프로퍼티가 있어야 사용 가능, key라는 키값이 있는 것이 아니다.

 

 

객체

자바스크립트는 객체 기반 프로그래밍 언어로 원시 값을 제외한 나머지 값(함수, 배열, 정규 표현식 등)은 모두 객체이다.

  • 객체 :  0개 이상의 프로퍼티로 구성 된 집합이며 
  • 프로퍼티:  객체의 상태를 나타내는 키(key)와 값(value)으로 구성된다. 
  • 메소드 : 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작(behavior)으로 프로퍼티 값이 함수일 경우.

 

객체 생성 방법

1. 객체 리터럴
2. Object 생성자 함수
3. 생성자 함수
4. Object.create 메서드
5. Class(ES6)
 
이 중 가장 일반적이고 간단한 방법이 객체 리터럴을 사용하는 방법이다.

-> 중괄호 내 0개 이상의 프로퍼티를 정의한다.

var student = {
	name : '유관순', // key값 : value값
    age : 16,
    getInfor : function(){
        return `${this.name}(은)는 ${this.age}세 입니다.`;
    }   // 메소드
};


console.log(typeof student);   // object
console.log(student);		   // { name: '유관순', age: 16, getInfor: [Function: getInfor] }

var student2 = {};  // 프로퍼티를 정의하지 않을 시 빈 객체 생성
console.log(typeof student2);  // objct
console.log(student2);		   // {}

 

프로퍼티 (속성)

프로퍼티 키 : 빈 문자열을 포함하는 모든 문자열 또는 심벌 값

문자열이므로 따옴표를 사용하지만 식별자 네이밍 규칙에 따르는 경우 사용하지 않아도 되며
식별자 네이밍 규칙을 따르지 않을 때에는 따옴표를 반드시 사용해야 한다. (하지만 규칙을 따를 것을 권장한다.)
 
프로퍼티 값 : 자바스크립트에서 사용할 수 있는 모든 값
 
 
var obj = {
    normal : 'normal value',
    '@ s p a c e @' : 'space value',    //특수문자 사용시에는 ''사용 
    '' : '',                            //빈 문자열 키는 오류 발생하지 않지만 권장하지 않음
    0 : 1,                              //숫자 키는 내부적으로 문자열로 변환
    var : 'var',                        //예약어 키는 오류 발생하지 않지만 권장하지 않음
    normal : 'new value'                //이미 존재하는 키를 중복 선언하면 나중에 선언한 프로퍼티로 덮어씀

}

console.log(obj);  //선언하는 순서대로 출력되진 않음. 내부적으로 결정됨.


// 출력 값
{
  '0': 1,
  normal: 'new value',
  '@ s p a c e @': 'space value',
  '': '',
  var: 'var'
}

 

메소드 

객체 내부에 정의된 함수로, 함수는 값으로 취급할 수 있고, 프로퍼티 값으로도 사용할 수 있다.

var dog = {
    name : '뽀삐',
    eat : function(food){
        console.log(`${this.name}(은)는 ${food}를 맛있게 먹어요.`);
    }

};

dog.eat('고구마');


// 출력 값
뽀삐(은)는 고구마를 맛있게 먹어요.

 

프로퍼티 접근

1. 마침표 표기법 (dot notation)
console.log(dog.name);    // 뽀삐
dog.eat('고고마');		   // 뽀삐(은)는 고고마를 맛있게 먹어요.​
 
2. 대괄호 표기법 (square bracket notation)
 

- 프로퍼티 키는 반드시 따옴표로 감싼 문자열을 사용한다.

console.log(dog['name']); // 뽀삐
  console.log(dog[name]);  // -> 출력X
dog['eat']('고구마'); // 뽀삐(은)는 고구마를 맛있게 먹어요.
 
 

- 프로퍼티 키가 식별자 네이밍 규칙을 준수하지 않는 이름일 경우 반드시 대괄호 표기법을 사용한다.

var obj = {
    'dash-key' : 'dash-value',
    0 : 1
};

//console.log(obj.dash-key);
//console.log(obj.'dash-key');
//console.log(obj[dash-key]);
//위의 경우 다 에러 

console.log(obj['dash-key']);    //dash-value

 

- 프로퍼티 키가 숫자로 이루어진 문자열인 경우 대괄호 표기법에서 따옴표를 생략할 수 있다.

//console.log(obj.0);
//console.log(obj.'0');
// 위의 경우 다 에러

console.log(obj[0]);    //1
console.log(obj['0']);  //1

 

프로퍼티 변경, 추가, 삭제

- 이미 존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신된다. 거듭 할당해도 마찬가지임

var dog = {
    name : '뽀삐'
};

dog.name = '두부';       
dog['name'] = '두부';
console.log(dog.name);   //두부

 

- 프로퍼티 동적 추가

존재하지 않는 프로퍼티 값을 할당하면 프로퍼티가 동적으로 생성되어 추가되고 프로퍼티 값이 할당된다.

dog.age = 3;
dog['age'] =3;
console.log(dog);   

// 출력 -> { name: '두부', age: 3 }

 

- 프로퍼티 삭제

delete 연산자는 객체의 프로퍼티를 삭제하며, 만약 존재하지 않는 프로퍼티를 삭제하면 에러없이 무시된다.
 
delete dog.age;
delete dog['age'];
console.log(dog);

// 출력 -> { name: '두부' }

delete dog.something;   // ->무시됨

 

 

ECMAScript(2020) - ES11에서 도입 된 연산자
 

1. 옵셔널 체이닝 연산자

 
좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.
 
 
옵셔널 체이닝 연산자 이전에는 논리 연산자 &&를 사용한 단축 평가를 활용했었는데 빈 문자열과 같은 Falsy 값을 false 취급해서 생기는 문제가 있다.

 

 

2. null 병합 연산자

좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고, 그렇지 않으면 좌항의 피연산자를 반환한다.
변수에 기본 값을 설정할 때 유용하다.
 
 
null 병합 연산자 이전에는 논리 연산자 || 를 사용한 단축 평가로 변수에 기본 값을 설정할 수 있었다.
단, 빈 문자열과 같은 Falsy 값을 false로 취급해서 생기는 문제가 있다.
 

'LECTURE > JavaScript' 카테고리의 다른 글

Object literal - ES6 , in 연산자, for in 반복문  (0) 2023.02.07
Object leteral - 객체, 프로퍼티, 메소드  (0) 2023.02.07
비교 연산자 & 단축 평가  (0) 2023.02.06
형변환  (0) 2023.02.06
변수 타입 & 동적 타입  (0) 2023.02.06

<비교 연산자>

  • 동등 비교 ( ==, != ) : 암묵적 타입 변환을 통해 타입 일치 시킨 후 같은 값인지 비교
  • 일치 비교 (===, !==) : 타입과 값이 모두 일치하는지 비교

 

- NaN은 자신과 일치하지 않는 유일한 값이다. 빌트인 함수 Number.isNaN을 사용해서 확인해야 한다.

 

- 비교 연산자를 통해 문자열끼리 비교도 가능하며 유니코드 순으로 비교한다.
 
  • 일치 비교 연산자
 
  • 대소 비교 연산자

<단축 평가>

표현식을 평가하는 도중 평가 결과가 확정 된 경우 나머지 평가 과정을 생략하는 것

1. &&, || 연산자 표현식의 결과는 때로는 불리언 값이 아닐 수도 있다.
  •   OR의 경우

'apple'이 이미 Truthy한 값이여서 true로 평가되고 논리 연산의 결과를 결정한 첫 번째 피연산자 'apple'을 그대로 반환한다.
 
 
  • AND의 경우
좌항, 우항 모두 확인해야 하므로 논리 연산의 결과를 결정하는 두 번째 피연산자 'banana'를 그대로 반환한다.

 

2. 단축 평가를 활용하면 if문을 대체할 수 있다.

 

3. 객체를 가리키기를 기대하는 변수가 null 또는 undefined가 아닌지 확인하고 프로퍼티를 참조할 때 

var obj = null;
var val = obj.value;
// TypeError: Cannot read properties of null (reading 'value')

 

obj가 Falsy(null, undefined) 값이면 좌항만 실행하여 val -> null

obj가 Truthy 값이면 val -> obj.value

 

+ Recent posts