sort 메소드

배열에서 sort 메소드를 활용하면 배열을 정렬할 수 있습니다.
sort 메소드에 아무런 argument도 전달하지 않을 때는 기본적으로 유니코드에 정의된 문자열 순서에 따라 정렬됩니다.

const fruit = ['banana', 'apple', 'orange'];
fruit.sort();
console.log(fruit);
// ['apple', 'banana', 'orange']

이렇게 유니코드에 정의된 문자열 숨서에 따라 정렬되기에,
만약 숫자를 정렬한다면 아래처럼 오름차순이나 내림차순 정렬이 되지 않습니다.

const numbers = [1, 4, 21, 3000]
numbers.sort();
console.log(numbers);
// [1, 21, 3000, 4]

숫자 정렬

그래서 숫자를 정렬하고 싶다면 아래처럼 콜백함수를 argument로 작성하면 됩니다.

const numbers = [1, 3000, 21, 4];

// 오름차순 정렬
numbers.sort((a, b) => a - b);
console.log(numbers);
// [1, 4, 21, 3000]

// 내림차순 정렬
numbers.sort((a, b) => b - a);
console.log(numbers);
// [3000, 21, 4, 1]

원본 배열 변경 없이 sort메소드 사용

여기서 주의할 점은 메소드를 실행하는 원본 배열의 요소들을 정렬한다는 점입니다.
그래서 다음처럼 3가지 방법으로 이를 피할 수 있습니다.

1. slice() 메소드 사용
const originalNumbers = [3, 1, 2];
const sortedNumbers = originalNumbers.slice().sort((a, b) => a - b);
console.log(originalNumbers);
// [3, 1, 2]
console.log(sortedNumbers);
// [1, 2, 3]
2. 스프레드 연산자(...) 사용
const originalNumbers = [3, 1, 2];
const sortedNumbers = [...originalNumbers].sort((a, b) => a - b);
console.log(originalNumbers);
// [3, 1, 2]
console.log(sortedNumbers);
// [1, 2, 3]
3. Array.from() 메소드 사용
const originalNumbers = [3, 1, 2];
const sortedNumbers = Array.from(originalNumbers).sort((a, b) => a-b);
console.log(originalNumbers);
// [3, 1, 2]
console.log(sortedNumbers);
// [1, 2, 3]

객체 배열 정렬

객체 배열은 다음처럼 정렬 할 수 있습니다.

const people = [
  { name: "Park", age: 31 },
  { name: "Kim", age: 24 },
  { name: "Lee", age: 34 },
];

people.sort((a, b) => a.age - b.age);
console.log(people);

예제 source code 링크

First-class Citizen(일급 객체)

First-class 는 값으로 취급 될 수 있는 모든 요소를 나타냅니다. 변수는 할당하거나 함수의 파라미터로 전달될 수 있는데 이러한 경우가 값으로 취급 될 수 있음을 말합니다. 즉, 변수는 First-class의 Citizen으로 간주되는 것입니다. 또 다른 First-class citizen의 예로는 정수, 문자열, 배열, 객체 등이 있습니다.

First-class Function(일급 함수)

First-class Function은 프로그래밍 언어중에서 함수를 First-class Citizen으로 취급하는 것을 말합니다. 즉, 함수를 변수에 할당하거나 파라미터로 전달하는 등을 할 수 있는 언어를 말합니다.

이러한 언어로는 python과 javascript 등이 있습니다.

python first-class function 관련 글 링크

First-class 예제

이 예제들은 First-class Function의 예제이면서 동시에 First-class Citizen의 예제입니다.

변수에 함수 할당

const add = function (a, b) {
  return a + b;
};

함수를 다른 함수의 인수로 전달

function sayHi(name) {
  console.log(`hi, ${name}`);
};

function greet(greeting, name) {
  greeting(name);
};

greet(sayHi, 'lee');      // hi, lee

다른 함수에서 함수 반환

function createMultiplier(multiplier) {
  return function (number) {
    return number * multiplier;
  };
};

const double = createMultiplier(2);

console.log(double(4));   // 8

Higher-order Function(고차 함수)

Higher-order Fuction은 하나 이상의 함수를 인수로 받거나 함수를 결과로 반환하는 함수입니다. 즉, 다른 함수에서 작용하는 함수입니다.

Higher-order Function 예제

map() function

const numbers = [1, 2, 3, 4, 5];

const squaredNumbers = numbers.map(function(number) {
  return number * number;
});

console.log(squaredNumbers);    // [ 1, 4, 9, 16, 25 ]

filter() function

const words = ['hello', 'world', 'javascript', 'programming'];

const shortWords = words.filter(function (word) {
  return word.length < 6;
});

console.log(shortWords);    // [ 'hello', 'world' ]

reduce() function

const numArray = [1, 2, 3, 4, 5];

const sum = numbers.reduce(function (acc, number){
  return acc + number;
}, 0);

console.log(sum);   // 15

일급 함수와 고차 함수의 차이점

이러한 점에서 일급 함수와 고차 함수의 차이점은 일급 함수는 값으로 취급할 수 있는 함수이고, 고차 함수는 다른 함수에 대해 연산을 할 수 있는 함수라는 점입니다. 다시 말하면 일급 함수는 프로그래밍 언어에서 값으로 취급할 수 있는 함수의 일종이고, 고차 함수는 다른 함수를 인자로 받거나, 인자로 돌려줌으로써 다른 함수에 작용하는 함수의 일종입니다. 즉, 모든 고차 함수는 일급 함수이지만, 모든 일급 함수가 고차 함수는 아닙니다.

function applyOperation(operation, a, b) {
  return operation(a, b);
}

const result = applyOperation(function (a, b) {
  return a + b;
}, 2, 3);

console.log(result);    // 5

즉 위의 예제는 고차 함수이면서 일급 함수인 예제입니다.

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

호이스팅(Hoisting)  (0) 2023.09.27
sort 메소드  (0) 2023.09.06
Named Function Expression(기명 함수 표현식)  (0) 2023.04.11
BigInt  (0) 2023.04.09
Primitive Type, Null과 undefined  (0) 2022.12.13

Named Function Expression (기명 함수 표현식)

예제 코드는 아래 링크에서 확인할 수 있습니다.

sourcecode

 

GitHub - yesaroun/JavaScriptStudy: javascirpt 공부

javascirpt 공부. Contribute to yesaroun/JavaScriptStudy development by creating an account on GitHub.

github.com

 

기명 함수 표현식은 함수 표현식으로 함수를 만들 때 함수 내부에 정의된 이름이 있는 함수 유형입니다.

이 이름은 식 내부에서 함수를 참조하는 데 사용할 수 있습니다.

아래 예시가 기명 함수의 예시입니다.

let myFunc = function hi() {
  console.log("hi!");
};

myFunc();   // hi!

다만 함수를 외부에서 함수를 호출할 때 사용할 수는 없습니다.

// hi();    // ReferenceError

 

기명 함수가 필요한 경우

기명 함수가 필요한 경우는 주로 재귀 함수를 사용하는 경우입니다.

 

예1 - countdown

let countdown = function (n) {
  console.log(n);

  if (n === 0) {
    console.log('End!');
  } else {
    countdown(n - 1);
  }
};

countdown(5);

만약 이 'countdown'함수를 복사하려고 다른 변수에 똑같이 담았다가, countdown 변수에 담긴 값이 변하게 되면 문제가 발생합니다.

let countdown = function (n) {
  console.log(n);
  if (n === 0) {
    console.log("END!");
  } else {
    countdown(n - 1);
  }
};

let myFunction = countdown;

countdown = null;

myFunction(5);    // TypeError

myFunction 함수를 호출했을 때, 함수가 실행되긴 하지만, 6번 줄 동작을 수행할 때 호출하려는 countdown 함수가 이미 12번에서 null 값으로 변경되었기 때문에 함수가 아니라는 TypeError가 발생한 것입니다.

이런 상황을 방지하기 위해서 함수 내부에서 함수 자신을 사용하려고 하면 함수표현식에서는 반드시 기명 함수 표현식을 사용하는 것이 좋습니다.

let countdown = function printCountdown(n) {
  console.log(n);
  if (n == 0) {
    console.log('End!');
  } else {
    printCountdown(n - 1);
  }
};

let myFunction = countdown;

countdown = null;

myFunction(5);

 

예2 - factorial

let factorial = function fact(n) {
  if (n === 0) {
    return 1;
  } else {
    return n * fact(n - 1);
  }
};

console.log(factorial(5));

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

sort 메소드  (0) 2023.09.06
일급 객체(First-class citizen)과 고차 함수(Higher-order function)  (0) 2023.04.12
BigInt  (0) 2023.04.09
Primitive Type, Null과 undefined  (0) 2022.12.13
Event Bubbling과 화살표 함수  (0) 2022.12.12

예제 코드는 예제 코드 주소 이 링크에서 확인할 수 있습니다.

BigInt는 ECMAScript 2020에 도입된 데이터 유형으로, 아주 큰 정수(Integer)를 표현하기 위해 등장한 데이터 타입입니다.

자바스크립트의 숫자에는 안전한 정수 표현의 한계가 있었습니다. 자바스크립트에서 안전한 최대 정수는 2**53 - 1인 'Number.MAX_SAFE_INTEGER'까지의 정수만 나타낼 수 있습니다. 안전한 정수 표현이라는 의미는 이 숫자 범위를 초과하는 정수를 나타내려고 하면 부정확한 계산이 되어 반올림 오류가 발생하기 때문입니다.

예를 들면, 9007199254740991 + 1과 9007199254740991 + 2를 비교하면 true라는 결과가 리턴됩니다. 실제로 콘솔에 9007199254740991 + 2과 심지어 9007199254740993을 출력해 봐도 9007199254740993이 아니라 9007199254740992가 출력되는 모습을 확인할 수 있는데요.

console.log(9007199254740991 + 1 === 9007199254740991 + 2); // true
console.log(9007199254740991 + 2);                          // 9007199254740992
console.log(9007199254740993);                              // 9007199254740992

이 숫자 범위는 JavaScript가 IEEE 754에 기술된 배정밀도 부동소수점 형식 숫자체계를 사용하기 때문입니다. 간단하게 말하면 '자바스크립트의 숫자형(number type) 값에는 9000조 정도의 정수 표현의 한계가 존재한다.' 입니다.

만약 number type의 범위를 넘어가는 계산을 할 때 BigInt라는 데이터 타입의 값을 사용하면 됩니다. BigInt 타입의 값은 일반 정수 마지막에 알파벳 n을 붙이거나 BinInt라는 함수를 사용하면 되는데요.

console.log(9007199254740993n); // 9007199254740993n
console.log(BigInt(9007199254740993)); // 9007199254740993

'BigInt' 타입도 'Number'타입과 마찬가지로 수학 연산에서 사용할 수 있습니다.

const bi1 = 12345678901234567890n;
const bi2 = 98765432109876543210n;

const sum = bi1 + bi2;
const difference = bi1 - bi2;
const product = bi1 * bi2;
const quotient = bi1 / bi2;

console.log(sum)        // 111111111011111111100n
console.log(difference) // -86419753208641975320n
console.log(product)    // 1219326311370217952237463801111263526900n
console.log(quotient)   // 0n

이러면 결괏값은 모두 'BigInt'를 반환합니다.

또한 'BigInt'는 비교 연산자를 사용하여 서로를 비교할 수 있습니다.

const bi3 = 12345678901234567890n;
const bi4 = 98765432109876543210n;

console.log(bi3 < bi4);   // true
console.log(bi3 === bi4); // false

이렇게 BigInt 타입을 사용하면 2**53 - 1 보다 큰 정숫값도 안전하게 표현할 수가 있습니다. 단, BigInt 타입에는 몇 가지 주의사항이 있는데요. 일단 BigInt 타입은 말 그대로 큰 정수를 표현하기 위한 데이터 타입이기 때문에 소수 표현에는 사용할 수가 없습니다.

1.5n; // SyntaxError

그래서 소수 형태의 결과가 리턴되는 연산은 소수점 아랫부분은 버려지고 정수 형태로 리턴됩니다.

console.log(10n / 6n);  // 1n
console.log(5n / 2n);   // 2n

그리고 BigInt 타입끼리만 연산할 수 있고, 서로 다른 타입끼리의 연산은 명시적으로 타입 변환을 해야 합니다.

// console.log(3n * 2);       // TypeError
console.log(Number(3n) * 2);  // 6

클래스형 컴포넌트와 함수형 컴포넌트

클래스형 컴포넌트

import {Component} from "react";

class App extends Component {
  render() {
    return (
      <div>
      </div>
    );
  }
}

export default App;

클래스형 컴포넌트는 리액트의 모든 기능을 활용할 수 있다.

함수형 컴포넌트

function App() {
  return (
    <div>
    </div>
  );
}

export default App;

함수형 컴포넌트는 기능이 부족했었다. state를 컴포넌트 내부에 만들 수 없다는 것과 라이프사이클 API도 사용할 수 없었다. 그래서 함수형 컴포넌트는 상위 컴포넌트가 전달하는 일만 단순하게 처리하는 역할이었다.

하지만, Hook이라는 개념이 도입되면서 함수형 컴포넌트에서도 state를 다룰 수 있고, 라이프사이클에 따라서 해야할 작업도 정의할 수 있게 되었다.

Props와 State의 차이

Props

간단히 하면 리액트에서 속성값을 나타내는 키워드이다.

App.js

import Content from "./components/Content";

function App() {
  return (
    );
}

export default App;

 

components/Content.js

function Content(props) {
  return (
    <div>
      <h1>{props.title}</h1>
      <img src={props.img} alt=""/>
      <p>{props.year}</p>
    </div>
  )
}

export default Content;

props를 사용한 간단한 예시로 부모 컴포넌트인 App.js로부터 props를 받고 자식 컴포넌트인 Content.js에서 사용한다. 다만 이 props는 상속받은 자식 컴포넌트 내에서 수정이 불가능하다. 이를 일방향성 상속이라고 한다.

State

State는 컴포넌트의 내부에서 선언되었으며 컴포넌트의 상태를 나타낸다.

App.js

import {Component} from "react";
import Content from "./components/Content";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
	      movie: {
        title: "클로저",
        img: "<https://the-take.com/images/uploads/screenprism/_constrain-480w/closer-3.jpg>",
        year: "2004"
      }
    }
  }

  render() {
    return (
    );
  }
}

export default App;
 

components/Content.js

function Content(props) {
  return (
    <div>
      <h1>{props.title}</h1>
      <img src={props.img} alt=""/>
      <p>{props.year}</p>
    </div>
  )
}

export default Content;

이는 state의 예제이다. App.js는 클래스형 컴포넌트로 작성되었다.

State와 Props 차이

State와 Props의 가장 큰 차이점은 props는 읽기 전용으로 수정이 불가하지만 State는 수정이 가능하다는 점이다.

또한 props는 함수형 컴포넌트, 클래스형 컴포넌트 모두 사용가능하지만 State는 클래스형 컴포넌트에서만 사용할 수 있었는데 리액트 16.8 버전부터 훅을 통해 구현이 가능하다.

 

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

명령형 프로그래밍과 선언형 프로그래밍  (0) 2024.02.12

undefined와 null 둘 다 Primitive Type(원시 타입)입니다.
우선 Primitive Type이 무엇인지 알아보고 이 둘의 차이점을 보겠습니다.

Primitive Type

다른 언어와 마찬가지로 JavaScript의 언어 타입도 크게 Primitive Type(원시 타입)과 Reference Type(참조 타입)으로 나뉩니다. 이 둘은 메모리에 저장되는 방식에 따라 나뉩니다.

Primitive Type과 Reference Type의 차이점은

  1. Premitive Type은 실제 데이터 값을 저장하고 Reference Type은 객체의 번지 주소를 저장해 메모리 번지 값을 통해 객체를 참조하는 타입입니다.
  2. Premitive Type은 변경 불가능한 Immutable Type이고, Reference Type은 변경이 가능한 가변성을 가진 mutable type입니다.

1번처럼 구분되는 이유는 사전에 얼만큼의 메모리를 할당할 수 있는지 알 수 있는 여부 때문입니다. 이걸 이해하기 위해서는 JavaScript나 Python 같은 동적 언어보다는 Java나 C 같은 정적 언어로 생각하면 편합니다.(동적 언어와 정적 언어의 설명은 아래 링크로 보면 이해되실 겁니다.) Java에서 Primitive Type인 정수는 4바이트 크기의 빈 방을 스택 메모리에 생성해서 사용합니다. 그래서 -2,147,483,648 ~ 2,147,483,647 사이의 정수만 입력이 가능합니다. 4바이트로 표현할 수 있는 숫자까지 저장할 수 있는 것입니다. 그래도 이렇게 Primitive Type의 경우 사전에 할당하는 메모리 크기를 정할 수 있는 자료형들입니다. 그래서 상대적으로 적은 용량이지만 액세스 속도가 매우 빠른 스택 메모리에 저장할 수 있는 것입니다. 하지만 만약 Reference Type인 객체를 저장한다고 하면 사전에 크기를 정하기 어렵습니다. 무작정 큰 저장 용량을 할당한다면 사용하지 않는 공간이 많아 메모리를 낭비할 수도 있고, 작은 저장 용량을 할당한다면 메모리가 부족해질 수도 있습니다. 그래서 액세스 속도가 느리지만 메모리 크기 제한이 상대적으로 여유로운 힙 메모리에 Reference Type을 저장합니다. 정확하게 Reference Type은 힙 메모리에 실제 데이터가 저장되어 있고 Stack메모리에는 Heap메모리의 주소가 저장되어 있습니다. 그래서 객체 번지 주소를 저장하는 것이죠. 이 설명이 자바스크립트에서도 크게 다르지 않습니다.

Primitive Type 종류

  • Boolean 타입
  • Undefined 타입
  • Null 타입
  • Number 타입
  • BigInt 타입
  • String 타입
  • Symbol 타입

이러한 타입이 있고 이 중, Undefined 타입과 Null 타입에 대해 더 알아보겠습니다.

Undefined

undefined는 Primitive Type으로 선언한 후에 값을 할당하지 않은 변수나 값이 주어지지 않은 인수에 자동으로 할당됩니다.

let a;
console.log(a);
//--==>> undefined

이렇게 선언만 하고 할당을 하지 않을 경우는 undefined가 출력됩니다. 즉, undefined는 자료형이 정의되지 않았을 때의 상태입니다. 그래서 변수가 undefined라면 아직 변수에 값이 할당되지 않았음을 의미합니다.

Null

null도 Primitive Type으로 이전에 값은 할당되었었지만 값이 더이상 유효하지 않음을 나타낼 때 사용합니다.

let b = 3;
b = null;
console.log(b);
//--==>> null

이 예시처럼 변수 b가 더이상 기존 값(3)이 유효하지 않음을 의미합니다. null은 변수를 초기화할 때 사용합니다.

참고로 undefined == null은 true이지만, undefined === null은 false 입니다. 이를 통해서도 이 둘은 자료형이 각각 undefined과 null로 다르다는 것을 알 수 있습니다.

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

Named Function Expression(기명 함수 표현식)  (0) 2023.04.11
BigInt  (0) 2023.04.09
Event Bubbling과 화살표 함수  (0) 2022.12.12
자바스크립트 문자열 객체  (0) 2022.07.22
자바스크립트 배열 객체  (0) 2022.07.22