Web/javascript

Node.js 이터레이터, 이터러블, 스프레드 연산자

dustKim 2024. 4. 23. 23:35
Node.js

- Node.js는 JavaScript 런타임 환경으로 서버 애플리케이션을 개발하는데 주로 사용된다.

  • function
더보기
function sum(num1, num2){
    console.log('sum() 호출!');
    return num1 + num2;
}

const result = sum(10, 20);
console.log(result);

console.log('-----------------');

// 함수의 메모리 주소 전달하는 방법 
const add = sum;
console.log(sum(10, 30));
console.log(add(10, 30));

console.log('-----------------');

// 함수의 작성팁
// 조건식이 있을 때 조건을 만족하지 않는 경우를 함수 도입부분에서 모두 처리 후 함수를 미리 종료
function print(num){
    if(num < 0) return;
    console.log(num);
}

print(10);
print(-5);

console.log('-----------------');

// 매개변수의 기본값을 무조건 undefined
// arguments: 함수의 전달된 인수에 해당하는 값을 array 형태의 객체로 반환
function total(num1, num2){
    console.log(num1);
    console.log(num2);
    console.log('arguments: ', arguments);
    console.log('arguments: ', arguments[0]);
    console.log('arguments: ', arguments[1]);
    return num1 + num2;
}

console.log(total());
console.log(total(10, 20));

console.log('-----------------');

// 콜백 함수 활용
const calc_add = (a, b) => a + b;
const calc_multiply = (a, b) => a * b;
console.log(calc_add(10, 20));
console.log(calc_multiply(10, 20));


// calculater(num1, num2, action)
function calculater(num1, num2, action){
    if(num1 < 0 || num2 < 0) return;

    const result = action(num1, num2);
    console.log(result);
    return result;
}

calculater(4, 2, calc_add);
calculater(4, 1, calc_multiply);
결과

 

nodejs에서 function의 기본값은 undefined이다.

arguments는 함수가 호출될 때 전달된 모든 인수를 포함하는 객체이다. 반환값은 배열과 비슷한 형태의 객체를 반환한다.

 

  • object
더보기
const Rucy = {
  name: "몽이",
  age: 14,
  weight: 3.5,
  ["height"]: 0.7,
  ["owner-name"]: "오너",
};

console.log(Rucy.name);
console.log(Rucy.weight);
console.log(Rucy.height);
// console.log(Rucy.owner-name);
console.log(Rucy["owner-name"]);

Rucy.family = "허스키";
console.log(Rucy.family);
console.log(Rucy["family"]);

console.log(Rucy);

delete Rucy["owner-name"];
console.log(Rucy["owner-name"]);
console.log(Rucy);

console.log("-------------------");

// 동적으로 프러퍼티에 접근하는 함수
function getValue(object1, key) {
  return object1[key];
}
getValue(Rucy, "name");
console.log(Rucy);

// 동적으로 요소를 추가하는 함수
function addKey(object2, key, value) {
  return (object2[key] = value);
}
addKey(Rucy, "owner-name", "오너");
console.log(Rucy);

// 동적으로 요소를 삭제하는 함수
function deleteKey(object4, key) {
  delete object4[key];
}
deleteKey(Rucy, "owner-name");
console.log(Rucy);

console.log("-------------------");

// 객체 생성 함수 만들기

// 좌표 객체 만들기
const x = 0;
const y = 0;
const coord = { x, y };
console.log(coord);

// 이름, 나이를 전달하여 객체로 만들어주는 함수 만들기
function makeObj(name, age) {
  return { name, age };
}

console.log(makeObj("오너", 20));

console.log("-------------------");

// 리터럴 표기법으로 객체 만들기
const apple = {
  name: "사과",
  display: function () {
    console.log(`${this.name}: 🍎`);
  },
};

const banana = {
  name: "바나나",
  display: function () {
    console.log(`${this.name}: 🍌`);
  },
};

console.log(apple);
apple.display();

console.log(banana);
banana.display();

// Fruit 생성자를 만들고 위 결과와 같은 동일한 결과를 출력하는 객체를 만들어보자.
// Fruit(name, emoji)
// const apple = new Fruit('apple', '🍎');
// console.log(apple);
// apple.display();

function Fruit(name, emoji) {
  this.name = name;
  this.emoji = emoji;
  this.display = () => {
    console.log(`${this.name}: ${this.emoji}`);
  };
}
const apple1 = new Fruit("apple", "🍎");
const banana1 = new Fruit("banana", "🍌");

console.log(apple1);
apple1.display();
console.log(banana1);
banana1.display();
결과

 

 

  • class
더보기
class Fruit{
    // static
    // 정적 프러퍼티 및 메서드를 생성
    // 클래스 레벨 메소드에서는 this를 참조할 수 없음
    static count_fruits = 10; 

    static makeBanana(){
        return new Fruit('banan', '🍌');
    }
    constructor(name, emoji){
        this.name = name;
        this.emoji = emoji;
    }

    display = () => {
        console.log(`${this.name}: ${this.emoji}`);
    }
}
const apple = new Fruit('apple', '🍎');
console.log(apple);
apple.display();

console.log('----------------');

console.log(Fruit.count_fruits);
const banana = Fruit.makeBanana();
console.log(banana);


console.log('-------------------');


// 객체지향 프로그래밍의 은닉성
// private

class Dog{
    #name; // private
    #color;
    constructor(name, color){
        this.#name = name;
        this.#color = color;
    }

    // 프러퍼티명과 setter 프러퍼티메서드의 이름은 일치할 필요없음
    set name(value){
        console.log('set', value);
        this.#name = value;
    }
    get name(){
        return this.#name;
    }

    set color(value){
        console.log('set', value);
        this.#color = value;
    }
    get color(){
        return this.#color;
    }

    run = () => {
        console.log(`${this.#color} 생삭의 강아지 ${this.#name}달립니다.`);
    }

    #eat = () => {
        console.log(`${this.#name} 사료를 먹습니다.`);
    }

    myEat = () => {
        this.#eat();
    }
}


const Rucy = new Dog('루시', '흰색');
console.log(Rucy);
console.log(Rucy.name);

// set 프러퍼티가 실행
Rucy.name = '복실';
// get 프러퍼티가 실행
console.log(Rucy.name);

Rucy.run();
Rucy.myEat();
결과

 

  • inherit
더보기
class Animal {
    constructor(color){
        this.color = color;
    }
    eat(){
        console.log('먹습니다.');
    }
    sleep(){
        console.log('잡니다.');
    }

    // 오버라이딩
    eat(){
        console.log('맛있게 먹습니다.');
    }
}

class Dog extends Animal{
    constructor(color){
        super(color);   // 부모에게 값을 넘겨줌..?
    }
    play(){
        console.log('놉니다.');
    }
}

const Rucy = new Dog('흰색');
console.log(Rucy);
Rucy.eat();
Rucy.sleep();
Rucy.play();
결과

 

이터레이터(Iterator)

- 이터레이터는 이터러블 객체를 통해 값의 시퀀스를 반복하는 데 사용되는 인터페이스, 반복자이다.

- next() 메서드를 구현하는 객체이다. (next() 메서드는 현재 요소를 반환하고 다음 요소로 이동하는 메서드이다.)

더보기
const arr = [1, 2, 3, 4, 5];
console.log(arr.values());
console.log(arr.entries());
console.log(arr.keys());

const iterator = arr.values();

while(true){
    const item = iterator.next();
    if(item.done) break;
    console.log(item.value);
}

for(let item of arr){
    console.log(item);
}
value 결과

 

value 값을 가져오기에 arr안에 있는 1~5까지 가져오게 된다.

 

keys 결과

 

key값을 가져오기에 arr안에 인덱스 0~4까지 가져오게 된다.

 

 

entries 결과

 

entries는 [ key, value ] 형태로 이루어져 있다. 그래서 값을 가져오면 [ key, value ] 형태로 가져오게 되는 것이다.

 

이터러블(Iterable)

- 이터러블은 반복 가능한 객체를 말하며,  [Symbol.iterator] 메서드를 구현해야 한다. 

- [Symbol.iterator] 메서드는 이터레이터를 반환하는 함수이다.

- 이터러블 객체는 for..of 루프나 배열 같은 반복 가능한 객체를 사용하는 문맥에서 반복될 수 있다.

더보기
function iterable(){
    let index = 0;
    let data = [1, 2, 3, 4];

    return {
        next(){
            if(index < data.length){
                return {value:data[index++], done:false};
            }
            else{
                return {value:undefined, done:true};
            }
        }
    }
}

let i = iterable();
console.log(i.next());
console.log(i.next());
console.log(i.next());
console.log(i.next());
console.log(i.next());
결과

 

위 코드를 보면 next() 메서드 내부에서 현재 인덱스의 길이를 초과하지 않는지 확인하고, 인덱스 길이를 초과하지 않으면 {value:data[index++], done:false} 를 반환하고, 길이를 초과하면 {value:undefined, done:true} 를 반환한다.

 

반복이 종료되면 iterable 함수를 호출하여 이터레이터 객체 i를 생성한다. 그 후 next() 메서드를 호출하여 반환된 값을 출력한다.

 

스프레드(Spread) 연산자

- 배열이나 객체를 펼쳐서 개별 요소로 분해할 수 있다. 즉, 배열이나 객체를 복사하거나, 다른 배열이나 객체에 요소를 추가하거나 결합할 때 유용하게 사용된다.

 

더보기
// 원시값과 객체값의 비교
// 원시값: 값에 의한 복사가 일어남
// 객체값: 참조에 의한 복사(메모리 주소)
function display(num) {
  num = 10;
  console.log(num);
}
const value = 5;
display(value);
console.log(value);
결과

 

원시값인 value의 값을 복사하여 num이라는 변수에 들어간 것이기 때문에 이후에 num 값이 변해도 원시값인 value의 값은 변경되지 않는다.

 

 

 

// 객체의 값을 변경하는 것은 좋지 않은 알고리즘
function displayObj(obj) {
  obj.age = 14;
  console.log(obj);
}
const Rucy = { name: "몽이", age: 15 };
displayObj(Rucy);
console.log(Rucy);
// 객체를 복사하여 age 를 변환하고 해당 객체를 반환
function changeAge(obj) {
  return { ...obj, age: 6 };
}
PPomi = changeAge(Rucy);
console.log(Rucy);
console.log(PPomi);
결과

 

첫 번째 호출에서 Rucy의 age 값을 14로 변경하고 출력이 된다. Rucy 객체에 age를 15로 바꿔도 displayObj를 호출하고 Rucy를 담았기 때문에 15가 아닌 14가 나오게 된다. 그 이후에도 Rucy의 age는 14로 유지가 된다.

하지만 두 번째 호출에서는  changeAge 함수가 Rucy를 복사하고 age 값을 6으로 변경했기 때문에 PPomi의 age는 6이 된다. 

즉, Rucy, PPomi 객체는 서로 다른 메모리 공간에 저장되어 있다는 것을 알 수 있다.

 

 

 

function add(num1, num2, num3) {
  return num1 + num2 + num3;
}
const nums = [10, 20, 30];
console.log(add(10, 20, 30));
console.log(add(nums[0], nums[1], nums[2]));
console.log(add(...nums));
console.log("--------------------");
const fruits1 = [":사과:", ":수박:"];
const fruits2 = [":바나나:", ":딸기:"];
let arr = fruits1.concat(fruits2);
console.log(arr);
arr = [...fruits1, ...fruits2];
console.log(arr);
arr = [...fruits1, "🍀", ...fruits2];
console.log(arr);
결과

 

숫자 합산에서는 첫 번째, 두 번째는 인덱스를 개별적으로 전달하여 계산을 한다. 마지막 세 번째는 Spread문법을 사용하여 배열을 펼쳐서 전달하여 같은 값이 반환된다.

 

과일 이름 나열에서는 첫 번째는 두 개의 배열을 concat을 사용하여 연결한 것이다.  두 번째는 Spread문법을 사용하여 concat과 같은 결과값을 반환한 것을 볼 수 있다. 세 번째는 이모티콘 문자열을 추가하여 Spread문법을 사용하여 연결한 것이다. 즉, Spread 문법은 배열을 합치거나 요소를 추가할 수 있다는 것을 알 수 있다.

더보기
const apple = {
  name: "몽주인",
  age: 20,
  address: { si: "서울시", gu: "송파구", dong: "석촌동" },
};
console.log(apple);
const new_apple = { ...apple, job: "프로그래머" };
console.log(apple);
console.log(new_apple);
결과

 

Spread 문법을 사용하여 사용하여 apple객체를 복사하여 new_apple 객체를 생성하고 속성을 추가한 것이다.

즉, apple 객체에는 속성이 추가되지 않고, 복사한 new_apple객체에만 속성이 추가된 것을 알 수 있다.

 

 

 

const fruits = ["🍏", "🍐", "🍑", "🍒", "🍓", "🍅", "🍆", "🌽"];
const [fruit1, fruit2, ...others] = fruits;
console.log(fruit1);
console.log(fruit2);
console.log(others);

function sendEmoji() {
  return ["🍏", "🍐", "🍑", "🍒", "🍓", "🍅", "🍆", "🌽"];
}

const [f1, f2, f3, f4, f5] = sendEmoji();
console.log(f1);
console.log(f2);
console.log(f3);
console.log(f4);
console.log(f5);
결과

 

fruits에서 첫 번째, 두 번째 요소를 출력하고, Spread문법을 사용하여 나머지 요소를 others 배열에 할당하고 출력이 된다.

 

sendEmoji 함수에서는 반환된 배열의 요소들을 차례대로 출력한다. 인덱스 0 ~ 4까지의 요소들이 출력이 된다.