분류 전체보기 (106)

📌  기본 문법

  • 출력: print("Hello, world!")
  • 주석: # 한 줄 주석, """여러 줄 주석"""
  • 변수 선언: 타입 없이 바로 사용
x = 10
name = "Alice"

🔢  기본 자료형

  • int, float, str, bool, None
  • 형 변환: int("10"), str(3.14), bool(0)

📚  자료구조

# 리스트
arr = [1, 2, 3]
# 튜플
tup = (1, 2)
# 집합
s = {1, 2, 3}
# 딕셔너리
d = {"a": 1, "b": 2}

🔁  조건문 & 반복문

# 조건문
if x > 0:
...
elif x == 0:
...
else:
...
# 반복문
for i in range(5):
print(i)
while x > 0:
x -= 1

🧩  함수

def add(a, b):
return a + b
# 기본값, 키워드 인자
def greet(name="Guest"):
print("Hello", name)
greet(name="Tom")

📦 클래스

class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f"Hi, I'm {self.name}")
 

⚙️ 기타 문법

  • 리스트 컴프리헨션
    squares = [x**2 for x in range(5)]
  • 람다 함수
    f = lambda x: x + 1
  • 예외 처리
try:
1 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
finally:
print("Done")
  • with 문 (컨텍스트 매니저)
with open("file.txt") as f:
data = f.read()

🧪 타입 힌트 (Python 3.5+)

def add(a: int, b: int) -> int:
return a + b

🧰 이터레이터 & 제너레이터

# 제너레이터 함수
def count_up():
yield 1
yield 2
for i in count_up():
print(i)
# 이터레이터
it = iter([1, 2, 3])
next(it) # 1

🏷 데코레이터

def decorator(func):
def wrapper():
print("Before")
func()
print("After")
return wrapper
@decorator
def hello():
print("Hello")
 

 

🧵 비동기 프로그래밍 (async/await)

import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
# asyncio.run(say_hello())

🔍 패턴 매칭 (Python 3.10+)

match command:
case "start":
print("Starting")
case "stop":
print("Stopping")
case _:
print("Unknown")

🪄 그 외 문법들(3.6~3.11에서 새로 추가된 것들)

📌 f-string (Python 3.6+)

name = "Alice"
print(f"Hello, {name}")

 

📌 변수 주석 (Python 3.6+)

age: int = 30

 

📌 := (해치 연산자, walrus operator / Python 3.8+)

if (n := len(data)) > 10:
print(f"Too long: {n}")

 

📌 exception group, except* (Python 3.11+)

try:
...
except* ValueError as e: # 여러 예외 동시 처리
...

⚙️ 모듈 & 패키지

# import 방식
import math
from math import pi, sqrt

📐 형 검사용 유틸 (typing 모듈)

from typing import List, Dict, Tuple
def process(data: List[int]) -> Dict[str, int]:
...

🧱 데이터 클래스 (Python 3.7+)

from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
 
 





 

'PYTHON' 카테고리의 다른 글

Python 기초를 배우며  (0) 2025.04.12

 

 

최근에 Python을 본격적으로 공부하기 시작했다. 개발을 한지는 꽤 됐지만, Python은 이상하게도 이제야 제대로 손을 대게 됐다. 다른 언어들을 사용해왔기 때문에 금방 익숙해질 줄 알았는데, 막상 공부를 시작하니 기존에 사용하던 언어와는 확실히 다른 점이 있어 시간이 걸렸다.


1. "가독성"이 핵심

 

가장 먼저 느낀 건 가독성을 정말 중요하게 여기는 언어라는 점이다.

들여쓰기로 코드 블록을 구분하는 건 처음에는 어색했는데, 쓰다 보니 이게 오히려 구조를 더 명확하게 보이게 해주는 것 같다.
중괄호가 없어서 단순해 보이기도 한다.

예를 들면 조건문도 이렇게 쓴다.

if x > 10:
print("x는 10보다 큽니다")
 

:와 들여쓰기로 흐름이 깔끔하게 표현된다.


2. 변수 선언이 자유롭다

타입을 명시하지 않아도 되고, 그냥 x = 10처럼 쓰면 된다.
처음엔 이게 좀 불안했다.
동적 타이핑 언어를 쓴 경험도 있었지만, 타입 안정성에 의존하는 스타일에 익숙해져 있어서 그런 것 같다.
하지만 Python은 그 자유로움을 활용하는 방식이 확실히 존재했다.

예를 들어,

name = "Alice"
count = 5
is_valid = True

변수 타입을 신경 쓰지 않아도 일단 코드가 자연스럽게 읽힌다. 물론 큰 프로젝트에서는 타입 힌트를 쓰는 식으로 보완할 수도 있다고 한다.


3. 문법이 깔끔하다

기본 문법 자체가 정말 단순하다. 복잡한 문법 요소가 없고, 오히려 너무 간결해서 약간 허전하게 느껴질 때도 있었다.
대신 읽고 쓰기 쉬운 코드가 된다는 점에선 꽤 강력한 장점이다.

반복문 예시:

for i in range(5):
print(i)

range() 덕분에 반복 횟수 제어가 편하고, 컬렉션 순회도 깔끔하게 된다.


4. 함수 정의도 간단하다

def greet(name):
return f"Hello, {name}!"
 

위는 f-string 문법을 활용했다.
문자열 포매팅이 간결하면서도 직관적이다.

하지만, f-string은 파이썬 3.6 버전부터 추가된 기능이다.


5. Python은 철학이 있는 언어다

재밌으면서 독특한 점은 import this 명령어를 치면 Python의 철학이 출력된다는 거다.

import this;
  • 출력된 결과물
 
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

그중에서도 마음에 들었던 문장은
"Simple is better than complex."
"Readability counts."
이다.

뭔가 Python이라는 언어가 단순한 문법 너머로 지향하는 방향성이 있다는 느낌을 받았다.


6. 활용 분야가 넓다

Python을 배우는 사람마다 진입 계기가 다르다고 들었다.
머신러닝, 데이터 분석, 웹, GUI까지 거의 못 하는 게 없다는 걸 알게 됐다.
"범용 언어"라는 말이 진짜 실감났다.


아직 Python의 얕은 물가에서 발 담근 정도지만, 확실히 매력 있는 언어라는 느낌은 받았다.
문법을 익히는 데 큰 어려움은 없었지만, 오히려 Python스럽게 작성하는 방식을 배우는 게 더 중요한 것 같다.
앞으로 프로젝트를 통해 조금씩 스타일을 잡아가면서 익숙해져야 할 것 같다.

 

 

 

'PYTHON' 카테고리의 다른 글

Python 3 문법 요약  (1) 2025.04.12

Spring Boot에서 효율적인 트랜잭션 관리 방법

Spring Boot 애플리케이션에서 트랜잭션 관리는 데이터 일관성을 유지하는 핵심 요소입니다. 올바르게 설정하지 않으면 데이터 손실이나 불일치 문제가 발생할 수 있습니다. 이번 글에서는 Spring의 트랜잭션 관리 전략효율적인 사용 방법을 정리해보겠습니다.


1.  트랜잭션 관리 방식

Spring Boot에서 트랜잭션을 관리하는 방법은 크게 두 가지로 나뉩니다.

 

1) 선언적 트랜잭션 관리 (@Transactional)

가장 일반적인 방식으로, 메서드나 클래스에 @Transactional 어노테이션을 사용하여 트랜잭션을 관리합니다.

  • 해당 메서드 실행 중 예외가 발생하면 자동으로 롤백
  • 커밋 또는 롤백을 신경 쓰지 않아도 되므로 유지보수가 용이

 

2) 프로그래밍 방식 트랜잭션 관리 (TransactionTemplate, PlatformTransactionManager)

트랜잭션을 직접 제어해야 할 때 사용합니다.

@Service
public class PaymentService {
private final TransactionTemplate transactionTemplate;
private final PaymentRepository paymentRepository;
public PaymentService(PlatformTransactionManager transactionManager, PaymentRepository paymentRepository) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.paymentRepository = paymentRepository;
}
public void processPayment(Payment payment) {
transactionTemplate.executeWithoutResult(status -> {
paymentRepository.save(payment); // 추가적인 비즈니스 로직 수행
});
}
}
  • 세밀한 트랜잭션 제어가 필요할 때 유용
  • 코드가 길어지고 복잡해질 수 있음

2. @Transactional 사용 시 주의할 점

1) 프록시 기반이므로 같은 클래스 내에서 호출하면 동작하지 않음

Spring의 @Transactional은 기본적으로 프록시 방식을 사용하기 때문에, 같은 클래스 내에서 트랜잭션 메서드를 호출하면 적용되지 않습니다.

잘못된 예:

@Service
public class UserService {
@Transactional
public void createUser(User user) {
saveUser(user);
}
public void saveUser(User user) {
// 같은 클래스 내 호출 → 트랜잭션이 적용되지 않음
userRepository.save(user);
}
}

 

해결 방법:

  • 외부에서 호출하도록 설계하거나, self-invocation 문제를 해결하기 위해 AOP를 활용합니다.
  • @Transactional을 사용하는 메서드를 다른 빈(Bean)에서 호출하도록 설계합니다.

2) readOnly 옵션을 적절히 활용하기

데이터 조회 시 @Transactional(readOnly = true)를 사용하면 성능 최적화에 도움이 됩니다.

@Transactional(readOnly = true)
public User getUser(Long id) {
return userRepository.findById(id).orElseThrow();
}
  • Hibernate는 readOnly = true일 때 더티 체킹(DIRTY CHECKING)을 수행하지 않으므로 성능이 향상됩니다.
  • 단, 읽기 전용 트랜잭션 내에서 save()를 호출하면 예외(Exception)가 발생할 수 있으므로 주의해야 합니다.

3. 트랜잭션 전파 옵션 (Propagation)

Spring은 트랜잭션이 중첩될 때 동작을 제어할 수 있도록 여러 가지 전파(Propagation) 옵션을 제공합니다.

  • 전파 옵션 종류
REQUIRED 기본값. 기존 트랜잭션이 있으면 참여, 없으면 새 트랜잭션 생성
REQUIRES_NEW 기존 트랜잭션을 무시하고 항상 새로운 트랜잭션 시작
NESTED 기존 트랜잭션 내에서 중첩 트랜잭션 실행
SUPPORTS 트랜잭션이 있으면 참여, 없으면 트랜잭션 없이 실행
NOT_SUPPORTED 트랜잭션 없이 실행
NEVER 트랜잭션이 있으면 예외 발생
MANDATORY 기존 트랜잭션이 없으면 예외 발생

 

@Service
public class NotificationService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendNotification(Notification notification) {
notificationRepository.save(notification);
}
}
 
  • REQUIRES_NEW를 사용하면 부모 트랜잭션과 별개로 커밋/롤백이 가능합니다.
  • 전파 옵션을 잘 활용하면 한쪽 로직이 실패해도 다른 트랜잭션이 영향을 받지 않도록 할 수 있습니다.

4. 트랜잭션 롤백 전략

1) 기본 롤백 동작

  • @Transactional은 체크 예외(Checked Exception) 발생 시 롤백하지 않고, 런타임 예외(Runtime Exception) 발생 시 롤백합니다.
@Transactional
public void processOrder() throws IOException {
// 체크 예외 throw new IOException("파일 처리 오류");
// 롤백되지 않음
}
@Transactional public void processPayment() {
throw new RuntimeException("결제 오류");
// 롤백됨
}
 

2) 특정 예외에 대해 롤백 설정

  • rollbackFor 옵션을 사용하여 특정 예외가 발생해도 롤백되도록 설정할 수 있습니다.
@Transactional(rollbackFor = IOException.class)
public void processFile() throws IOException {
throw new IOException("파일 처리 오류"); // 롤백됨
}
  • 반대로, 특정 예외에서 롤백되지 않도록 noRollbackFor 옵션을 사용할 수도 있습니다.
@Transactional(noRollbackFor = IllegalArgumentException.class)
public void updateUser(User user) {
throw new IllegalArgumentException("잘못된 입력"); // 롤백되지 않음
}

 

Spring Boot에서 트랜잭션을 적절히 관리하면 데이터 무결성을 보장하고 성능을 최적화할 수 있습니다.

@Transactional을 적극 활용하되, 내부 호출(self-invocation) 문제를 주의
읽기 전용 트랜잭션(readOnly = true)을 적절히 활용하여 성능을 최적화
Propagation 옵션을 이해하고, 비즈니스 로직에 맞게 선택
체크 예외와 런타임 예외를 rollbackFor, noRollbackFor를 통해 롤백 여부 제어

 

 

 

오늘 오전 유튜브에서 가격을 인상한다는 메일을 받았다..

 

유튜브 프리미엄은 2016년 한국에서 서비스를 시작하여 지금까지 거의 가격이 변동되지 않고 동일한 가격에 운영되었다.

유튜브 프리미엄은 구글에서 운영중인 유튜브라는 세계 최대 규모의 비디오 플랫폼인 유튜브의 유료 구독 서비스이다.

프리미엄을 사용하면 비디오 중간마다 있던 광고가 없어지고, 유튜브 뮤직(Youtube Music)이라는 서비스를 이용할 수 있다.

 

유튜브 프리미엄 가격 인상 메일

 

나는 유튜브 프리미엄을 오랫동안 이용해 왔다.

영상을 보다 중간에 광고가 뜨는 것을 참지 못해서(ㅋㅋ) 프리미엄을 끊을 수가 없었다.

8,690원이라는 저렴한 가격으로 지금까지 인상되지 않고 이용할 수 있어서 좋았는데..

이 메일을 보니까 그냥 유튜브 광고보면서 시청해야하나라는 생각이 잠시나마 들었다.

 

넷플릭스도 가구 추가할 때마다 5천원 추가로 매달 청구한다그러고... ㅋㅋㅋ 요즘엔 흔한 일이다.

 

그나마 다행인건 기존의 프리미엄 고객은 3달 동안은 기존 가격 그대로 사용할 수 있게 해준다는 것이었다.

이번의 구글이 프리미엄 가격을 인상하면서 보낸 메일 내용은 꽤나 괜찮았다.

가격을 인상한다는 내용 밑에 바로 기존 고객은 최소 3개월 더 연장해드립니다.  라고 되어있어 기존 고객이 적어도 3달 동안은 기존 금액 그대로 이용할 수 있게 한 것이다.

그리고 바로 밑에 언제든지 구독을 취소할 수 있다고 하면서 취소하러가는 링크까지 걸어줬다.

이정도면 꽤 소비자의 마음을 신경써서 배려를 해준것이란 생각이 든다.

 

어쨋든 한국에서 유튜브 프리미엄 변동된 가격은

안드로이드 기준 14,900원 IOS 기준 19,500원 이다.

 

IOS를 이용하는데 너무 비싸다면 결제할 때만 안드로이드나 웹으로 결제하면 14,900원에 구독할 수 있다~

 

 

 

 

 

 

 

Vue와 NativeScript를 사용하여 하이브리드 앱을 개발하려고 설치하고 있었다.

NativeScript-Vue 앱 프로젝트를 만드는 방법은 공식사이트에 잘 정리되어 있다. (한국어 버전은 아무래도 업데이트가 느려서 영어 버전을 읽는 것이 가장 최신 정보를 볼 수 있다!)

https://nativescript-vue.org/ko/docs/introduction/

 

NativeScript-Vue - A NativeScript plugin for building truly native applications using Vue.js

A NativeScript plugin for building truly native applications using Vue.js

nativescript-vue.org

 

MAC OS에서 NativeScript 셋팅하기

https://docs.nativescript.org/setup/macos

 

Setting up macOS for NativeScript | NativeScript

Setting up macOS for Android You will need Node, NativeScript CLI (command line interface), Android Studio and a JDK (java development kit). Android Studio is not strictly necessary — however it provides an easy-to-use interface for installing and managi

docs.nativescript.org

 

NativeScript와 구동하는데 필요한 android studio및 xcode와 cocoapods, xcodeproj를 모두 설치한 후 첫 ns 프로젝트에 신나는 마음으로 ns 상태 확인하는 명령어인 ns doctor ~와 nativescript --version 을 터미널에 입력해서 상태를 확인하였다.

그런데 공식문서를 따라서 정상적으로 메뉴얼대로 설치했는데 node module이 호환되지 않는 문제가 발생하였다.

분명..모두 제대로 설치되었는데... xcode 최신 버전 다운로드하면서 MAC 현재 최신 os인 sonoma로 업데이트까지 해놓은 상태였다..

J in ~ λ nativescript --version
node:internal/modules/cjs/loader:927
throw err;
^
Error: Cannot find module 'node:process'
Require stack:
- /Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/node_modules/marked-terminal/index.cjs
- /Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/common/logger/logger.js
- /Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/common/yok.js
- /Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/bootstrap.js
- /Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/nativescript-cli.js
- /Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/bin/tns
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:924:15)
at Function.Module._load (node:internal/modules/cjs/loader:769:27)
at Module.require (node:internal/modules/cjs/loader:996:19)
at require (node:internal/modules/cjs/helpers:92:18)
at Object.<anonymous> (/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/node_modules/marked-terminal/index.cjs:3:17)
at Module._compile (node:internal/modules/cjs/loader:1092:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1121:10)
at Module.load (node:internal/modules/cjs/loader:972:32)
at Function.Module._load (node:internal/modules/cjs/loader:813:14)
at Module.require (node:internal/modules/cjs/loader:996:19) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/node_modules/marked-terminal/index.cjs',
'/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/common/logger/logger.js',
'/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/common/yok.js',
'/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/bootstrap.js',
'/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/lib/nativescript-cli.js',
'/Users/J/.nvm/versions/node/v15.14.0/lib/node_modules/nativescript/bin/tns'
]
}

 

터미널에서 nativescript와 그 외 프로그램들을 여러번 install과 uninstall을 반복했는데 node:process 모듈을 찾지 못한다고 계속 실행을 못하고 있다... node process 모듈은 실행에 반드시 필요한 필수 모듈인데 이것도 여러번 깔았다 지웠다를 반복했다.😭

그래서 유튜브와 ns 공식디코채널 등을 뒤져서 하나의 아이디어를 찾을 수 있었다. 

바로 nativescript 최신 버전이 아직 apple silicon arm의 호환이 완벽하진 않을 수 있다는 생각이 들었다. 그래서 nativescript를 지운후 바로 이전 버전으로 설치하였더니 문제가 해결되었다.

npm install -g nativescript@8.5.3
J in ~ λ nativescript --version
8.5.3
ℹ New version of NativeScript CLI is available (8.6.1), run 'npm i -g nativescript' to update.

 

정확하게 호환이 왜 안되는지 내 컴퓨터에서만 안된 건지는 모르겠지만 ns를 다운그레이드하니까 같은 오류가 뜨지 않았다!

 

문제는 여기서 끝나지 않았다... android studio 설치하면서 android sdk와 필요한 옵션을 모두 설치하였는데 호환이 안된다고 한다. NativeScript를 다운그레이드하면서 android, ios(cocoapods,xcodeproj) 모두 맞는 버전으로 설치해주어야 호환이 되는 것으로 보인다.

J in ~ λ ns doctor android
✔ Getting environment information
TIP: To avoid setting up the necessary environment variables, you can use the Homebrew package manager to install the Android SDK and its dependencies.
There seem to be issues with your configuration.
✔ Getting NativeScript components versions information...
⚠ Update available for component nativescript. Your current version is 8.2.3 and the latest available version is 8.6.1.
✔ Your ANDROID_HOME environment variable is set and points to correct directory.
✔ Your adb from the Android SDK is correctly installed.
✔ The Android SDK is installed.
✔ Javac is installed and is configured properly.
✔ The Java Development Kit (JDK) is installed and is configured properly.
✖ Cannot find a compatible Android SDK for compilation. To be able to build for Android, install Android SDK 28 or later.
Run `$ sdkmanager` to manage your Android SDK versions.
✖ No compatible version of the Android SDK Build-tools are installed on your system. You can install any version in the following range: '>=23 <=32'.
Install the required build-tools through Android Studio. In case you already have them installed, make sure the `ANDROID_HOME` environment variable is set correctly.
Your environment is not configured properly and you will not be able to execute local builds.

 

그래서 아래와 같이 android sdk 버전을 변경하였다.
android studio > More Actions > SDK Manager
- Hide Obsolete Packages 체크 해제
- Show Package Details 체크
- SDK Platforms 에서 Android 12L 다운 후 적용
- SDK Tools에서 Android SDK Build-Tools 32.0.0 다운 후 적용

android sdk도 다운그레이드 하고나니 제대로 동작했다.😂

J in ~ λ ns doctor android
✔ Getting environment information
No issues were detected.
✔ Your ANDROID_HOME environment variable is set and points to correct directory.
✔ Your adb from the Android SDK is correctly installed.
✔ The Android SDK is installed.
✔ A compatible Android SDK for compilation is found.
✔ Javac is installed and is configured properly.
✔ The Java Development Kit (JDK) is installed and is configured properly.
✔ Getting NativeScript components versions information...
⚠ Update available for component nativescript. Your current version is 8.2.3 and the latest available version is 8.6.1.

 

ios는 xcode 15.0.x 버전에서 ns 8.5.3이랑 호환이 되었다. (다행이다...)

cocoapods와 xcodeproj가 호환이 안되었는데 공식문서에서 ruby gem을 설치할때 2.7버전으로 설치해서 너무 이전버전이라 안 맞는 것 같다. 그래서 최신 ruby로 설치 후(환경변수도 ruby@2.7이라고 하면 안된다!!) 다시 cocoapods와 xcodeproj를 설치하니까 잘 돌아갔다. 😅 개발환경 셋팅부터가 만만치 않은 ns였다..





결론

Device : Mac M1
OS : sonoma 14.1.1
NativeScript : 8.5.3
android sdk : android 12L
xcode : 15.0.x

 

 

 

 

 

 

▶︎ 이벤트

 

🍘  자바스크립트에서 이벤트란?

 

이벤트(event)는 웹 브라우저나 사용자가 실행하는 어떤 동작

 

- 클릭하거나 마우스를 올리는 등의 모든 동작

- 웹 브라우저에서 일어난 모든 동작이 이벤트가 되진 않고 해당 웹 문서 영역에서 이루어지는 동작만

 

 

🍏 문서 로딩 이벤트

 

이벤트 이벤트가 발생하는 순간
abort 웹 문서가 완전히 로딩하기 전에 불러오기를 멈추었을 때
error 문서가 정확히 로딩되지 않았을 때
load 문서 로딩이 끝났을 때
resize 문서 화면의 크기가 바뀌었을 때
scroll 문서 화면이 스크롤 되었을 때
unload 문서를 벗어날 때

 

 

🍏 마우스 이벤트

 

이벤트 이벤트가 발생하는 순간
click 요소를 클릭했을 때
dblclick 더블클릭했을 때
mousedown 마우스 버튼을 눌렀을 때
mousemove 마우스 포인터를 움직일 때
mouseover 마우스 포인터를 요소 위로 옮길 때
mouseout 마우스 포인터가 요소를 벗어날 때
mouseup 요소 위에 올려놓은 마우스 버튼에서 손을 뗄 때

 

 

🍏 키보드 이벤트

 

이벤트 이벤트가 발생하는 순간
keydown 키를 누르는 동안
keypress 키를 눌렀을 때
keyup 키에서 손을 뗄 때

 

 

🍏 폼(form) 이벤트

 

이벤트 이벤트가 발생하는 순간
blur 폼 요소에 포커스를 잃었을 때
change 목록이나 체크 상태 등이 변경되었을 때
(input, select, textarea 태그에서 사용)
focus 폼 요소에 포커스를 놓았을 때
(label, select, textarea, button 태그에서 사용)
reset 폼이 리셋되었을 때
submit submit 버튼을 클릭했을 때

 

 

▶︎ 이벤트 처리하기

 

이벤트를 처리하는 것을 '이벤트 처리기' 또는 '이벤트 핸들러' 라고 함

 

🍏 HTML 태그에 함수 연결하기

HTML 태그에 'on이벤트명' 으로 직접 함수를 연결할 수 있음

<태그 on이벤트명="함수명">

이 방법은 함수에 변경 내용이 있으면 HTML 소스도 함께 수정해야 해서 스크립트 파일에서 이벤트 처리하는 방법을 많이 사용

 

🍏 웹 요소에 함수 연결하기

 

요소.on이벤트명 = 함수

이 방법을 이용해서 하나의 이벤트에 두가지 이상의 함수를 실행할 경우 가장 마지막에 사용한 것만 적용되서 문제

 

 

🍏 이벤트 리스너로 이벤트 처리하기

 

addEventListner() 메서드를 사용해서 이벤트 처리하는 방식을 많이 사용함

요소.addEventListner(이벤트, 함수, 캡처 여부);

- 이벤트 : 이벤트 명엔 on을 붙이지 않고 'click' 처럼 이벤트 이름 그대로 사용

- 함수 : 익명함수를 사용해서 직접 작성해도 되고 호출해도됨 (호출할 경우 괄호 붙이면 안됨!)

- 캡처 여부 : true면 캡처링을, false이면 버블링을 한다는 의미, 대부분 기본값인 false 그대로 둠

 

 

▶︎ event 객체

 

웹 문서에 발생하는 이벤트 정보를 저장하는 event 객체가 있다.

 

🍘 event 객체의 프로퍼티와 메서드

 

event 객체는 이벤트 이름, 발생위치, 발생시간 등 이벤트와 관련된 다양한 정보가 포함되어 있다.

event 객체에서 사용할 수 있는 메서드는 preventDefault() 뿐임

 

🍏 event 객체의 주요 프로퍼티

 

프로퍼티 기능
button 마우스 키값을 반환한다
clientX / clientY 이벤트가 발생한 가로 / 세로 위치를 반환한다
pageX / pageY 현재 문서를 기준으로 이벤트가 발생한 가로 / 세로 위치를 반환한다
target 이벤트가 발생한 대상을 반환한다
timeStamp 이벤트가 발생한 시간을 밀리초 단위로 반환한다
altKey / shiftKey / ctrlKey 이벤트가 발생할 때 alt / shift / ctrl 키를 누르고 있었는지의 여부를 불리언 값으로 반환한다
type 발생한 이벤트 이름을 반환한다
which 키보드와 관련된 이벤트가 발생했을 때 키의 유니코드 값을 반환한다

 

※ 전체 프로퍼티 목록 링크

 

event 객체 프로퍼티 사용 예시

const box = document.querySelector("#box");
box.addEventListner("click", (e) => {
alert(`이벤트 발생 위치 : ${e.pageX}, ${e.pageY}`);
});

pageX와 pageY라는 프로퍼티를 사용해서 이벤트 객체의 위치를 알 수 있다.

 

웹 문서에서 마우스 오른쪽 버튼 비활성화하기

window.addEventListner("contextmenu", e => {
e.preventDefault();
alert("오른쪽 버튼을 사용할 수 없습니다");
});

마우스 오른쪽 버튼을 클릭하면 나오는 바로가기 메뉴를 콘텍스트 메뉴(context menu)라고 한다.

웹에서 마우스 오른쪽 버튼을 사용하지 못하게 할 때 위와 같이 많이 사용한다.

 

 

▶︎ 이벤트 전파

 

이벤트가 발생할 때 그 부모 요소에도, 부모의 부모요소에도 똑같이 이벤트가 처리되는데, 이것을 "이벤트 전파(event propagation)"이라고 한다.

 

 

🍘 이벤트 버블링

 

특정 요소에서 이벤트가 발생 -> 그 요소의 부모 요소 -> 부모 요소의 부모 요소

이런식으로 부모요소에도 이벤트가 발생한것으로 간주되어 전파되는 것을 이벤트 버블링이라고 한다.

웹 브라우저 상의 대부분의 이벤트는 이벤트 버블링 된다.

 

 

🍏 event.target과 event.currentTarget

 

event 객체의 프로퍼티 중에 target과 currentTarget 프로퍼티가 있는데 target은 이벤트가 발생한 맨 처음 요소를 가리키고  currentTarget은 이벤트가 전파되면서 현재 이벤트 처리기가 실행되는 대상을 가리킨다.

 

 

🍘 이벤트 캡처링

 

이벤트 캡처링은 웹 요소에서 이벤트가 발생하면 일단 최상위 요소에서 시작해서 이벤트가 발생한 요소까지 차례대로 이벤트가 전파되는 방식이다.

버블링이 아래에서 위로(자식에서 부모로) 전파된다면 캡처링은 위에서 아래로(부모에서 자식으로) 전파된다.

이벤트 리스너에 세번째 옵션에 true를 사용하면 캡처링 방식으로 전파된다.

 

 

 

 

 

 

▶︎ DOM

 

🥥 DOM 이란?

 

DOM (Document Object Model, 문서 객체 모델)

- 웹 문서에 담겨 있는 모든 요소를 따로 제어 ➡️ 조건에 맞거나 사용자 동ㅇ작이 있을 때 웹 문서 전체 또는 일부분이 동적으로 반응

- DOM에서는 웹 문서를 하나의 객체로 정의

- 텍스트, 이미지, 표 등 모든 요소를 각각 객체로 정의

- 웹 문서들도 객체이므로 프로퍼티, 메서드를 갖고 있음

 

 

🥥 DOM 트리

 

- 웹 문서는 여러가지 태그가 서로 포함 관계('부모', '자식')를 가지고 있음

- DOM을 활용해 웹 문서의 요소를 부모와 지식으로 구분해서 표시하면 트리모양이 되서 DOM 트리라고 부름

- 노드(node) : DOM 트리에서 가지가 갈라져 나가는 부분

- 루트 노드(root node) : html 노드

- 형제 노드(sibling node) : 같은 부모를 가진 노드

 

 

🥥 웹 요소에 접근하기

 

 

🍎 querySelector() 함수

 

- 선택자를 사용해 웹 요소의 1가지만 가져올 때 사용

- document 객체에 포함된 함수

document.querySelector("p") // p태그 요소 중 첫번 째 요소
document.querySelector("#container") // id가 container인 요소
document.querySelector(".box") // class가 box인 요소 중 첫번째 요소

- 조건에 맞는 요소가 여러개 일 경우 첫번째 요소 1개만 가져옴

 

 

🍎 querySelectorAll() 함수

 

- 한꺼번에 여러개 요소를 가져와 노드 리스트 형태로 저장

- 노드 리스트에 저장된 요소는 배열처럼 인덱슬ㄹ 사용해서 접근

 

 

🍎 웹 요소 내용 수정하기

 

- 프로퍼티를 사용

웹요소.innerText
웹요소.innerHTML
웹요소.textContent

 

innerText  : 웹 브라우저 창에 보이는 내용만 가져옴 (감춰진 것은 안보임)

innerHTML  : 요소 안에 있는 태그 내용을 함께 가져옴

textContent  : 소스에 있는 대로 요소의 내용을 가져옴 (감춰진 것까지 보임)

 

- 내용을 가져와서 내용 수정하기

웹요소.innerText = 내용
웹요소.innerHTML = 내용
웹요소.innerContent = 내용

 

- 이미지 요소에 접근 후 src 속성값 바꾸기

이미지 요소.src = 이미지 파일

 

 

🥥 자바스크립트로 스타일 수정하기

 

🍎 css 속성에 접근해서 수정하기

 

요소.style.속성명

 

const button = document.querySelector("button");
button.onclick = () => {
button.style.backgroundColor = "black";
button.style.color = "white";
}

 

 

🍎 classList

 

- 클래스 스타일을 추가 또는 삭제 가능

- classList 는 요소에 사용한 클래스 스타일을 모두 모아 놓은 프로퍼티

요소.classList;		// 요소에 사용된 클래스 리스트 모두 볼 수 있음

 

- 스타일을 추가, 삭제하거나 토글하기

요소.classList.add(클래스명)
요소.classList.remove(클래스명)
요소.classList.toggle(클래스명)

 

- 특정 클래스 스타일이 있는지 확인하기

요소.classList.contains(클래스명)

 

 

🥥 DOM에서 폼 다루기

※ 폼(form) : 사용자가 내용을 입력할 수 있는 웹 요소

 

 

🍎  텍스트 값 가져오기

 

요소.value
document.querySelector("#name-box").value

 

 

🍎 name 속성값을 사용해 폼 요소에 접근하기

 

<form name="order">
...
<input name="product">

HTML에서 위와같이 있을경우 input 박스에 접근할 때 아래와 같이 name으로 접근할 수 있다.

document.order.product.value

 

 

🍎 form 배열을 사용해서 접근하기

 

document.forms // 모든 form을 가져옴
document.forms[0].elements // 첫번째 form에 있는 폼 요소를 모두 가져옴
document.forms[0].elements[0] // 첫번째 form 요소에 첫번째 요소를 가져옴

 

 

🍎 선택 목록, 항목에 접근하기

 

- HTML에서 selector를 사용한 선택 목록의 option(항목)에 접근할 때 아래와 같은 방법을 사용할 수 있다.

document.querySelector("#product").options

- HTMLOptionsCollection 형태로 저장

- selectedIndex 에는 사용자가 선택한 옵션의 인덱스 값이 저장 (기본값 0)

➡️ selectedIndex를 활용해 사용자가 선택한 값을 가져올 수 있음

 

 

🍎 체크박스, 라디오 버튼에 접근하기

※ 체크박스 : 여러가지 항목 중 여러개를 선택할 수 있음

※ 라디오박스 : 여러가지 항목 중 한가지만 선택할 수 있음

 

<h1>메뉴 주문</h1>
<form name="orderForm">
<fieldset>
<legend>메뉴</legend>
<p>메뉴를 선택하세요</p>
<label><input type="checkbox" name="menu" value="dolce">돌체라떼</label>
<label><input type="checkbox" name="menu" value="vanilla">바닐라라떼</label>
<label><input type="checkbox" name="menu" value="choco">초코라떼</label>
</fieldset>
<fieldset>
<legend>구매수단</legend>
<p>구매 수단을 선택하세요</p>
<label><input type="radio" name="purchase" value="card">카드</label>
<label><input type="radio" name="purchase" value="cash">현금</label>
<label><input type="radio" name="purchase" value="gifticon">기프티콘</label>
</fieldset>
</form>

 

- label 태그에 type 속성으로 checkbox인지 radio인지 구분

- 같은 그룹 별로 같은 name 붙임

 

- 라디오 버튼에 접근하기

document.orderForm.purchase

name을 사용해 접근

RadioNodeList 라는 노드 리스트 형태로 저장됨

선택한 항목은 value 값이 RadioNodeList의 value에 저장됨

 

- 체크 박스에 접근하기

document.orderForm.menu

마찬가지로 name 으로 접근

 

document.orderForm.menu[0].value	// 'dolce'

인덱스로 접근해서 특정값을 가져올 수 있음

 

- checked 속성

라디오 버튼, 체크 박스에는 checked 속성이 있음

선택했으면 true, 선택하지 않았으면 false

document.querySelectorAll("input[name='menu']:checked")	// 메뉴 중 선택된 항목만 가져옴

 

 

 

 

 

 

 

 

🧀  함수

 

🥨  함수 선언하기

 

function 함수명(매개변수) {
명령들
}
function example(a, b) {
console.log(`${a}, ${b}`);
}

 

 

🥨  함수 호출하기

 

example(10, 20);	// "10, 20" 출력

 

 

- 매개변수, 인수, return은 다른 언어와 동일하게 사용한다.

 

 

🥨  기본 매개변수

 

- 에크마스크립트 2015부터 새롭게 생긴 기능

- 함수를 선언할 떄 매개변수의 기본값을 지정할 수 있음

- 값을 전달받지 못한 매개변수 값이 undefined가 되어 결과가 NaN 이 되는 것을 방지

 

function sum(a, b = 1, c = 2) {
return a + b + c;
}
console.log(sum(3, 4, 5)); // 12
console.log(sum(3, 4)); // 9
console.log(sum(3)); // 6

 

 

 

🧀  스코프

 

🥨  스코프(scope), 란?

 

- 선언한 변수의 적용 범위

- 어느 위치에서 변수에 접근할 수 있는지를 가리킴

 

 

🥨  지역 스코프

 

- 변수를 특정 영역에서만 사용할 수 있을 때 '지역 스코프를 가지고 있다'고 함

- 지역 스코프를 가지고 있는 변수를 '지역 변수'라고 함

- var 예약어(ES6이전) 를 사용해서 변수를 함수내에서 선언할 경우 지역 스코프를 가짐

 

 

🥨  전역 스코프

 

- 프로그램 시작 부분에서 변수를 선언하면 프로그램 전체에서 사용할 수 있음

- 전역 스코프를 가지고 있는 변수를 '전역 변수'라고 함

- var 예약어를 사용하지 않으면 어디서 선언하든 전역 변수로 인식함

- let, const 예약어로 사용한 변수는 '스크립트 스코프'를 가진다고 함

 

 

🥨  블록 스코프

 

- 중괄호 {} 에 둘러싸인 영역 내에서 유효한 변수를 '블록 스코프를 가진다'고 함

- let, const 를 사용해 만든 변수는 블록 스코프를 가짐 (블록 변수)

 

 

 

🔥  자바스크립트 변수 주의사항

 

var 변수보다 let, const 변수를 사용한다

전역 변수는 최소한으로 사용한다

객체 선언은 const를 사용한다

 

 

 

🧀  함수 표현식

 

 

🥨  익명 함수

 

- 함수에 이름이 없는 함수

 

변수에 할당해서 사용하는 익명 함수

 

let multiply = function(a, b) {
return a * b;
}

 

- 함수를 마치 하나의 값처럼 사용할 수 있음

- 함수를 변수에 할당할 수도 있고, 함수를 다른 함수의 매개변수로 넘길 수도 있음

 

 

🥨  즉시 실행 함수

 

- 한번만 실행하는 함수일 경우 함수를 정의하면서 동시에 실행할 수도 있음

- 함수를 식 형태로 선언하므로 마지막에 세미콜론 (;) 붙여야함

 

(function(매개변수) {
...
} (인수);
(function(a, b) {
console.log(a*b);
} (5, 10); // 콘솔 창에 '50'출력

 

 

🥨  화살표 함수

 

- 에크마스크립트 2015 부터 => 를 이용한 화살표 표기법을 사용함

- 함수를 더 간단하게 선언할 수 있어서 많이 사용

 

(매개변수) => {함수 내용}

 

 

매개변수가 없을 때

const hi = () => {
return 'hi';
}

- 괄호() 안에 비워둠

 

 

함수가 한줄일 때

const hi = () => return 'hi';

- 중괄호 생략 가능

 

 

함수식에 return문만 있을 때

const hi = () => 'hi';

- return 도 생략가능

 

 

매개변수가 1개일 때

const hi = user => console.log(`${user}님, 안녕하세요`);

- 매개변수의 괄호() 생략 가능

 

 

매개변수가 2개 이상일 때

const hi = (user, id) => console.log(`${id}, ${user} 님 안녕하세요`);

 

 

🥨  콜백 함수(callback function)

 

- 콜백 함수는 다른 함수의 인수로 사용하는 함수이다.

- addEventListner() 함수에서 함수를 인수로 넣는데 이렇게 다른 함수의 인수가 되는 함수를 콜백 함수라고 함

- 다른 언어와 다르게 자바스크립트에서는 함수이름에 괄호를 제외하고 이름만 작성해서 함수를 호출하는 대신 변수처럼 넣을 수 있음

 

const button = documnet.querySelector("button");
function display() {
alert("클릭!");
}
button.addEventListner("click", display);

 

 

 

▶  자바스크립트에서는 함수가 1급 시민

 

- 1급 시민(first-class citizen) 조건

1. 변수에 할당할 수 있어야 한다.

2. 다른 함수의 인자로 사용할 수 있어야 한다.

3. 다른 함수에서 반환값으로 반환할 수 있어야 한다.

 

자바스크립트는 '함수'가 1급 시민이다.

 

 

 

🧀  전개 구문

 

전개구문(spread syntax)은 배열처럼 값이 다양한 자료를 한꺼번에 인수로 넘겨주거나 배열과 배열을 합할 때처럼 배열을 하나의 덩어리로 처리해야할 때 유용하다.

 

🥨  전개 구문 작성 방법

 

colors = ["black", "white", "red", "blue", "green"];
console.log(...colors);
/*
black white red blue green
*/

 

- 다른 정보는 필요없고 값만 꺼내 사용하려고 할 때 전개 구문 유용

 

 

🥨  나머지 매개변수

 

- 함수를 선언할 때 나중에 몇 개의 인수를 받게 될지 알 수 없는 경우 사용 (나머지 매개변수)

 

const add(...numbers) {
let sum = 0;
for (let number of numbers) {
sum += number;
}
return sum;
}

 

- 일부분은 변수로 받고 그 외에는 나머지 매개변수로 받을 수도 있음

 

const add(first, ...numbers) {
let sum = first;
for (let number of numbers) {
sum += number;
}
return sum;
}

 

 

 

🧀  타이머 함수

 

- 자바스크립트에서 특정 시간이 되었을 때 함수를 실행하거나 특정 시간 동안 함수를 반복하는 등 시간을 재는 함수가 있음 (타이머 함수)

- 실행할 함수와 시간을 인수로 지정

 

 

🥨  일정 시간마다 반복 - setInterval()

 

setInterval(콜백 함수, 시간)

 

- 시간은 밀리초 단위 사용 (1000밀리초 = 1초)

- 콜백 함수를 미리 선언했다가 인수로 전달해도 되고 함수 표현식으로 선언하면서 동시에 실행 가능

 

 

🥨  반복 실행 멈추기 - clearInterval()

 

clearInterval(타이머)

 

- setInterval() 함수를 실행하면 웹 브라우저를 종료하기 전까지 실행됨

- setInterval() 의 반복을 멈추는 함수

- setInterval() 에 타이머 이름을 지정해줄 수 있어서 clearInterval() 괄호안에 이름을 넣어서 지정

 

const timer = setInterval(() => {
console.log("hi?");
}, 3000);
clearInterval(timer); // 타이머 종료

 

- 보통 특정 횟수 또는 시간만큼 반복 후 종료하도록 설정함

 

 

🥨  특정 시간 이후에 실행하기 - setTimeout()

 

- 지정한 시간이 지난 후에 콜백 함수 실행

 

setTimeout(콜백 함수, 시간)

 

 

 

 

 

 

 

 

 

 

이 책은 빌게이츠도 추천한 책이다.

워낙 유명해서 알고는 있었지만 한번도 관심이 안갔었는데 서점에서 조금 읽어보니까 흥미로워서 바로 충동적으로 사버렸다.

이 책은 사람들이 본능적으로 하게되는 오해에 대해서 직관적이면서 이해가 쉽도록 잘 풀어서 쓴 책이다.

저자는 이 책을 아들 며느리와 함께 집필하였는데 이 책을 출간하기 전에 세상을 떠났다.

저자는 다양한 단체와 기업, 유명인사들을 만나면서 사람들이 세계에 대해 오해하고 있는 부분을 강연하고 다닌 사람이었다.

나도 마찬가지로 세계에 대해서 오해하고 있는 사람중 한명이었고 이 책 덕분에 내가 본능적으로 오해를 하고 얼마나 왜곡된 시각을 갖고 있는지 알게 되었다.

현대시대에서 많은 정보와 통계가 오픈되어 있고 인터넷으로 전세계가 연결되어 있지만 사람들은 세계를 보는 시각이 왜곡되었다고 소개해준다.

 

사람들은 '개발도상국'과 '선진국' 이란 단어로 서로 큰 차이가 있다 생각하고 그 사이엔 국가가 없거나 적다고 생각한다. (간극 본능)

하지만 사실 개발도상국과 선진국으로 나눌수 있을 정도로 세계는 나뉘어 있지 않고 세계적으로 기술의 발전과 노력으로 이미 대부분 많은 개발도상국이었던 나라들은 커다란 발전을 이루어서 개발도상국이라 부르는 것은 실례이다.

대신 저자는 소득에 따른 4개의 단계로 나누어서 1단계부터 4단계로 나누어서 표현하라고 추천해준다.

내가 보기에도 두개로 나누는 것보다 4단계로 나누는게 더 올바르다고 생각한다. 하지만 나도 이 책을 읽기 전까지는 오해를 하고 있었고 아직도 아프리카와 동아시아를 제외한 다른 아시아 국가들은 개발도상국이라고 생각하고 있었다.

 

이런 오해는 사람들이 일부러 하거나 누군가 세뇌를 한 결과물이 아니라 저자는 인간의 본능에서 나오는 오해라고 얘기한다.

집 밖에 야생동물들이 다니는 시대에는 위험으로부터 몸을 보호하기 위해 이러한 본능들이 반드시 필요했지만 이제는 그런 시대는 지나갔고 그런 위험은 밖에 없다. 그래서 그런 위험에서 지키던 본능으로 사람들이 세계를 이상하게 왜곡해서 보고있다고 해석한다.

 

앞서 소개한 간극본능 처럼 다른 본능들이 사람들이 세계를 오해하게 한다.

저자가 소개한 본능은 간극본능, 부정본능, 직선본능, 공포본능, 크기본능, 일반화본능, 운명본능, 단일관점본능, 비난본능, 다급함본능 총 10가지 이다. 각 장에서 하나씩 소개하면서 적절한 일화와 어떻게 이 본능이 잘못되었고 도표와 자료들을 통해 왜 틀렸는지 설명해주었다.

이 책 덕분에 올바르게 세계를 볼 수 있는 시각이 생겼고 전체를 보는 올바른 틀을 갖게 되었다. 또한 전세계가 얼마나 발전했으며 그만큼 기아와 아동사망률이 줄어서 희망이 있고 절망적이지만은 않다는 것을 알게 되었다. 그리고 전세계에 대한 시각 뿐 아니라 어떠한 현상을 볼 때 전체적인 것을 냉정하고 올바르게 분석하는 사고방식을 알게 되어 고마운 책이다.

 

이 책은 전체를 보는 통찰력이 필요한 사람에게 적극 추천한다. 조직에서 의사 결정권을 갖고있는 사람이거나 전체적인 시장을 분석해야하는 사람에게는 필수적이다.

이런 사람의 본능을 이해하지 못한 채로 전체를 해석하려고 하거나 무언가를 결정하려고 한다면 잘못된 결과가 나올 수도 있을 것이다.

요즘 사람들은 너무 자극적인 자료로 편파적이게 세상을 보고 점점 시스템이 복잡해지다보니 전체를 보는 능력이 떨어진다. 그래서 자기가 하는 역할에만 집중해서 그런지 전체적인 시각은 많이 부족하다고 느낀다.

그래서 사실 누구나 읽을 필요가 있다고 생각된다. 📚 😄

 

 

 

 

 

 

'etc.' 카테고리의 다른 글

'몰입(황농문 저)'를 읽고...  (1) 2023.07.10

 

 

자바스크립트에서 NaN은 비교연산자(==, ===, !=, !== 등) 으로 비교가 안된다. 왜냐하면 NaN은 자기자신과 비교해도 다르다고 하기 때문이다!! (https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/NaN)

 

NaN - JavaScript | MDN

전역 NaN 속성은 Not-A-Number(숫자가 아님)를 나타냅니다.

developer.mozilla.org

 

 

let temp = Number("안녕하세요"); // temp는 NaN이 된다.
temp === NaN // false!⚠️

 

자바스크립트는 자료형이 자꾸 바뀌어서 골치아픈데 NaN에서 직접비교하면 원하는 결과가 안나온다. 😭

NaN인제 체크하고 싶다면 함수를 사용하면된다!

또는 자기 자신과 다른지 체크하면 된다.. NaN은 유일하게 자기과 비교했을 때 다르다고 하는 값이다. 

function valueIsNaN(num) {
return num !== num; // NaN을 제외한 모든 값은 false, NaN만 유일하게 true로 나온다.
}

 

 

🌟  Object.is()

 

Object.is() 는 객체안의 두 값이 같은지 비교해주는 함수이다.

let isNaN = NaN;
Object.is(isNaN, NaN) // true!

이 함수를 사용해서도 가능한데 MDN NaN문서에서는 isNaN() 함수를 추천해준다.

 

 

🌟 isNaN()

 

isNaN()Number.isNaN() 두가지 방법이 있는데 혼동해서는 안된다.

isNaN() 은 현재 값이 NaN이거나 숫자로 바꾸었을 때 NaN 인경우 true 이다.

Number.isNaN() 은 현재 값이 NaN 이어만 true 이다.

 

isNaN('NaN인가요?') // true
Number.isNaN('NaN인가요?') // false

 

NaN 인지 비교할 때 상황에 맞춰서 적절한 함수를 사용하면 될 것이다.

 

1 2 3 4 ··· 11