리스트, 딕셔너리, 튜플, 세트

 

리스트 [a, b, ...]

 리스트는 객체의 집합으로, 순서를 가지고 있다.

subway = [10, 20 ,30]

subway = ['유재석', '조세호', '박명수']
print(subway.index('조세호')) # '조세호'의 index

subway.append('하하') # 리스트 뒤에 '하하'를 추가

subway.insert(1, '정형돈') # index 1에 '정형돈'을 추가
print(subway) # ['유재석', '정형돈', '조세호', '박명수', '하하']

subway.pop() # 맨 뒤의 요소 1개 제거

 index를 통해 요소가 위치한 곳의 정보를 알 수 있고 append, insert, pop을 통해 요소를 추가하거나 삽입할 수 있다.

 

# 리스트 정렬
numList = [5, 2, 4, 3, 1]
numList.sort()

# 리스트 순서 뒤집기
numList.reverse()

# 리스트 내 요소 모두 지우기
numList.clear()

# 리스트는 다양한 자료형을 포함하여 사용할 수 있다.
numList2 = [9, 20, 1, 33]
mixList = ['조세호', 20, True, numList2]
print(mixList) # ['조세호', 20, True, [9, 20, 1, 33]]

# 리스트는 확장이 가능하다.
numList3 = [1, 2, 3, 4, 5]
mixList.extend(numList3)
print(mixList) # ['조세호', 20, True, [9, 20, 1, 33], 1, 2, 3, 4, 5]
print(mixList[0])

 

 sort, reverse를 통해 순서를 정렬할 수 있다. 그리고 리스트는 또다른 리스트나 Boolean, 문자열, 숫자형 등 다양한 자료형을 포함할 수 있다. extend를 통해 확장 또한 가능하다.

 

딕셔너리 {key1: value, key2: value2, ...}

 JavaScript의 Object, 즉 객체와 유사하다. key에 따른 value를 가진 요소들을 담고 있는 집합이다.

 

딕셔너리에서 value를 가져오는 방법

cabinet = {3:'유재석', 100:'김태호'}
print(cabinet[3])
print(cabinet[100])
# print(cabinet[0])
print(cabinet.get(3))
print(cabinet.get(0)) # get을 사용하여 없는 key를 불러올 때는 에러가 아니라 None을 반환한다.
print(cabinet.get(5, '사용 가능')) # get을 사용하였을 때 None이라면 '사용 가능'을 대신 반환한다. 즉 -1 -> '사용 가능'

 딕셔너리 뒤에 [] 안에다가 key값을 작성하면 된다. 만약 존재하지 않는 key값을 작성하면 error가 발생한다. get을 사용하여 value를 가져올 수도 있는데, get은 존재하지 않는 key을 값을 넣었을 때 error를 내지 않고 -1을 반환한다. 이 때 2번째 인자를 삽입하면, 존재하지 않는 key값을 넣었을 때 -1이 아니라 두 번째 인자를 반환한다.

 

# 해당 key가 dictionary에 있는지 확인
print(3 in cabinet) # True
print(5 in cabinet)

# 새로운 key/value 추가
cabinet = {'A-3': '유재석', 'B-100': '김태호'}
print(cabinet)
cabinet['A-3'] = '김종국'
cabinet['C-20'] = '조세호'
print(cabinet)

# key/value 삭제
del cabinet["B-100"] # del은 작은 따옴표, 큰 따옴표를 구분하지 않는다.
print(cabinet)

# key들만 출력
print(cabinet.keys())

# value들만 출력
print(cabinet.values())

# key/value 쌍으로 출력
print(cabinet.items())

# 모든 key/value 삭제
cabinet.clear() # 리스트와 마찬가지로 clear 사용
print(cabinet)

 key in 딕셔너리를 통해 해당 key가 딕셔너리에 존재하는지 확인할 수 있다. 그리고 [] 안에 새로운 key 값을 넣고 = 뒤에 value를 넣어 새로운 key/value 요소를 추가할 수 있다. del을 통해 간단하게 요소를 삭제할 수 있고 keys와 values로 key값들 혹은 value값들만 출력할 수 있다.

 

튜플 (a, b, ...)

 튜플은 리스트와 유사해 보이나, 내용 변경이나 추가는 할 수 없다. 따라서 유연하진 않지만 처리 속도가 빨라진다. 내용 변경이 필요없는 곳에 사용할 때 효율적이다.

menu = ('돈까스', '치즈까스') # 튜플은 [], {}가 아니라 ()을 사용한다.
print(menu[0])
# menu.append('생선까스') # 튜플에서는 요소 추가 등의 변경이 불가능하여 에러가 발생한다.

 

# 튜플의 활용
name = '김종국'
age = 20
hobby = '코딩'
print(name, age, hobby)
(name, age, hobby) = ('김종국', 20, '코딩')
print(name, age, hobby)

 

세트 {a, b, ...}

 집합, 즉 세트(set)는 중복을 허용하지 않고, 순서가 없다.

my_set = {1, 2, 3, 3, 3} # 딕셔너리와 달리 key가 없다.
print(my_set) # 뒤에 중복되는 3들이 없어진다.

 

java = {'유재석', '김태호', '양세형'} # 주의하자. 딕셔너리가 아니라 세트이다.
python = set(['유재석', '박명수']) # set를 생성하는 다른 방법.
print(python) # 세트의 경우 순서가 상관없기 때문에 '박명수'가 앞으로 올 수도 있다.

 

# 요소 추가
python.add('김태호') # 세트에서 요소를 추가하는 방법은 add이다.
print(python)

# 요소 삭제
java.remove('김태호')
print(java)

 세트에서는 add와 remove를 통해 요소를 추가하거나 삭제할 수 있다.

 

교집합, 합집합, 차집합

# 교집합
print(java & python) # {'유재석'}
print(java.intersection(python)) # intersection은 교차라는 뜻

# 합집합
print(java | python) # '유재석'은 중복되지 않는다. {'양세형', '유재석', '박명수', '김태호'}
print(java.union(python))

# 차집합
print(java - python) # java 집합에서 java & python 교집합을 빼는, 오직 java에만 포함되어 있는 요소들. {'양세형', '김태호'}
print(java.difference(python))

 

자료구조의 변경

menu = {'커피', '우유', '주스'} # 세트 {}
print(menu, type(menu)) # menu의 type도 같이 출력된다.

menu = list(menu) # 리스트로 변경 []
print(menu, type(menu)) # menu의 type으로 리스트가 출력된다.

menu = tuple(menu) # 튜플로 변경 ()
print(menu, type(menu)) # menu의 type으로 튜플이 출력된다.

menu = set(menu) # 세트로 변경 {}
print(menu, type(menu))

menu = dict(menu) # 딕셔너리로 변경 {key: value, ...}
print(menu, type(menu)) # {'주': '스', '우': '유', '커': '피'} <class 'dict'>

 python에서는 이렇게 자료구조의 변경이 가능하다.

 

퀴즈

'''
Quiz) 당신의 학교에서는 파이썬 코딩 대회를 주최합니다.
참석률을 높이기 위해 댓글 이벤트를 진행하기로 하였습니다.
댓글 작성자들 중 추첨을 통해 1명은 치킨, 3명은 커피 쿠폰을 받게 됩니다.
추첨 프로그램을 작성하시오.

(조건)
1. 편의상 댓글은 20명이 작성하였고 아이디는 1 ~ 20이라고 가정
2. 댓글 내용과 상관 없이 무작위로 추첨하되 중복 불가
3. random 모듈의 shuffle과 sample 활용

(출력 예제)
 -- 당첨자 발표 --
치킨 당첨자 : 1
커피 당첨자 : [2, 3, 4]
 -- 축하합니다. --

(활용 예제)
from random import *
list = [1, 2, 3, 4, 5]
print(list)
shuffle(list)
print(list)
print(sample(list, 1))
'''

 

나의 풀이

from random import *

list = list(range(1, 21)) # 1 부터 21 직전까지, 즉 1 ~ 20까지의 숫자 리스트를 형성한다.
# print(type(range(1, 21))) # 참고로 range의 type은 range이다.
shuffle(list) # shuffle을 통해 list를 무작위로 섞어준다.

chicken = sample(list, 1) # list에서 무작위로 샘플 1개를 뽑는다.
list.remove(chicken[0]) # 중복을 피하기 위해 chicken으로 뽑힌 값은 list에서 삭제
# print(chicken) # sample은 list에서 샘플 1개를 뽑아 리스트 형태로 반환해준다는 것을 알 수 있다.

coffee = sample(list, 3)

print(' -- 당첨자 발표 -- ')
print('치킨 당첨자 :', chicken[0]) # 쉼표를 사용했기 때문에 str(chicken[0])을 해주지 않아도 된다.
print('커피 당첨자 :', coffee)
print(' -- 축하합니다. -- ')

 정상적으로 동작을 하지만 인자가 바뀌면 수정해야할 부분이 비교적 많다.

 

나도코딩님 풀이

from random import *

users = range(1, 21)
users = list(users)

shuffle(users)
winners = sample(users, 4)

print(' -- 당첨자 발표 -- ')
print('치킨 당첨자 : {0}'.format(winners[0]))
print('커피 당첨자 : {0}'.format(winners[1:]))
print(' -- 축하합니다. -- ')

 훨씬 깔끔하고 중복도 쉽게 피해간다.

'프로그래밍 > Python' 카테고리의 다른 글

조건문과 반복문  (0) 2022.03.08
문자열  (0) 2022.03.04
연산자  (0) 2022.03.03
자료형  (0) 2022.03.03

 조건문과 반복문

if

weather = input('오늘 날씨는 어때요? ') # input을 이용해 다음과 같이 작성 후 실행 시 커서가 ? 뒤에서 기다리고 있다. 사용자가 입력한 값은 문자열로 저장된다. 
if weather == '비' or weather == '눈':
    print('우산을 챙기세요.')
elif weather == '미세먼지':
    print('마스크를 챙기세요.')
else:
    print('준비물이 필요 없어요.')

temp = int(input('기온은 어때요? ')) # 정수형으로 입력값을 받고 싶을 때
if 30 <= temp:
    print('너무 더워요, 나가지 마세요.')
elif 10 <= temp and temp < 30:
    print('괜찮은 날씨에요.')
elif 0 <= temp < 10:
    print('외투를 챙기세요.')
else:
    print('너무 추워요, 나가지 마세요.')

 if 문을 통해 원하는 조건에 맞는 코드를 실행시킬 수 있다. 그리고 만약 처음 if의 조건에 성립하지 못했다면 elif를 만나고, 이러한 if 와 elif 모두의 조건에 성립할 수 없다면 else로 넘어가게 된다.

 

 위 코드에서 쓰인 input을 통해서 사용자가 입력한 입력값을 받을 수 있다.

 

for

for waiting_no in [0, 1, 2, 3, 4]:
    print("대기번호: {0}".format(waiting_no))

for waiting_no in range(5): # 0 부터 5 직전까지
    print('대기번호: {0}'.format(waiting_no))

for waiting_no in range(1, 5): # 1부터 5 직전까지
    print('대기번호: {0}'.format(waiting_no))

starbucks = ['아이언맨', '토르', '아이엠 그루트']

for customer in starbucks:
    print('{0}, 커피가 준비되었습니다.'.format(customer))

 for문을 통해서 원하는 만큼 코드를 반복적으로 실행할 수 있다.

 

students = [1, 2, 3, 4, 5]
print(students)
students = [i + 100 for i in students] # students의 각 요소를 i로 불러오면서 그 i에 100 더한 값을 students 리스트에 넣어라.
print(students)

students = ['Iron man', 'Thor', 'I am groot']
print(students)
students = [len(i) for i in students]
print(students)

students = ['Iron man', 'Thor', 'I am groot']
print(students)
students = [i.upper() for i in students]
print(students)

 이렇게 리스트 안에서 반복을 진행하여 각 요소의 값을 바꿀 수 있다. 첫 번째 students는 [101, 102, 103, 104, 105]가 되었을 것이다. 두 번째 students 리스트는 각 요소가 길이로 반환되어 [8, 4 ,10]이 된다. 세 번째 students는 모두 대문자로 바뀌게 된다.

 

while

customer = '토르'
index = 5
while index >= 1:
    print("{0}님, 커피가 준비 되었습니다. {1}번 남았습니다.".format(customer, index))
    index -= 1
    if index == 0:
        print('커피는 폐기처분되었습니다.')

 while 문은 조건을 만족하는 한, 계속해서 while 밑의 코드가 실행된다. 위 코드는 index가 점차 5, 4, 3, 2, 1로 줄어들면서 5번 반복하게 되고 0이 되면서 index >= 1을 만족하지 못하게 되기 때문에 while문이 종료된다.

 

customer = '아이언맨'
index = 1
while True:
    print('{0}님, 커피가 준비되었습니다. 호출 {1}번 했습니다.'.format(customer, index))
    index += 1

 이처럼 코드를 작성 시, 계속해서 True이기 때문에 무한 루프에 빠지게 된다. 터미널에서 index가 계속해서 증가하는 것을 목격할 수 있다.

무한루프, 터미널 창 클릭 후 ctrl + c(윈도우)로 빠져나올 수 있다.

 

customer = '토르'
person = 'Unknown'

while person != customer:
    print('{0}님, 커피가 준비되었습니다.'.format(customer))
    person = input('이름이 어떻게 되시나요? ')
    if person == '토르':
        print('네, 감사합니다.')

 위 코드에서는, input에서 사용자가 토르라고 입력하지 않으면 while문이 계속해서 실행된다. 사용자가 토르라고 입력하면 person = '토르'가 되고 if문을 실행하여 '네, 감사합니다.'를 실행시킨다. 그리고 person != customer는 False가 되어 while이 종료된다.

 

continue, break

absent = [2, 5]
noBook = [7]

for student in range(1, 11):
    if student in absent:
        continue # continue를 만나면 밑에 있는 문장을 실행하지 않고 다음으로 넘어간다. 즉 2나 5에서는 책 좀 읽어줘를 실행하지 않고 3과 6으로 넘어가게 된다.
    elif student in noBook:
        print('오늘 수업은 여기까지. {0}은 교무실로 따라와'.format(student))
        break # break를 만나면 곧바로 반복문이 종료된다. 즉 7에서는 8로 넘어가는 것이 아니라 반복문을 종료시킨다.
    print('{0}, 책 좀 읽어줘.'.format(student))

 continue를 만나면 밑의 코드를 무시하고 다음 차례로 넘어간다. 즉 if문에서 현재 student가 absent와 동일한 2라면 continue가 실행된다. 따라서 '책 좀 읽어줘'라는 print문이 실행되지 않고 student는 3으로 넘어가게 된다.

 

 break를 만나면 반복문을 종료시키게 된다. 만약 현재 student가 noBook과 동일한 7이라면 elif문의 코드가 실행되고 print문이 실행되면서 while이 멈추게 된다. break는 다음 차례로 넘어가는 continue와는 다르게 8로 넘어가지 않고 7에서 for문을 종료한다는 것이다.

 

퀴즈

'''
Quiz) 당신은 Cocoa 서비스를 이용하는 택시 기사님입니다.
50명의 승객과 매칭 기회가 있을 때, 총 탑승 승객 수를 구하는 프로그램을 작성하시오.

조건1 : 승객별 운행 소요 시간은 5분 ~ 50분 사이의 난수로 정해집니다.
조건2 : 당신은 소요 시간 5분 ~ 15분 사이의 승객만 매칭해야 합니다.

(출력문 예제)
[O] 1번째 손님 (소요시간 : 15분)
[ ] 2번째 손님 (소요시간 : 50분)
[O] 3번째 손님 (소요시간 : 5분)
...
[ ] 50번째 손님 (소요시간 : 16분)

총 탑승 승객 : 2 분
'''

 

# while 사용
currPassenger = 1
passCount = 0

while currPassenger < 51:
    leadTime = randint(5, 50)
    if 5 <= leadTime <= 15:
        print('[O] {0}번째 손님 (소요시간 : {1})'.format(currPassenger, leadTime))
        passCount += 1
    else:
        print('[ ] {0}번째 손님 (소요시간 : {1})'.format(currPassenger, leadTime))
    currPassenger += 1

print('총 탑승 승객 : {0} 분'.format(passCount))

 

count = 0

for i in range(1, 51):
    leadTime = randrange(5, 51)
    if 5 <= leadTime <= 15:
        print('[O] {0}번째 손님 (소요시간 : {1})'.format(i, leadTime))
        count += 1
    else:
        print('[ ] {0}번째 손님 (소요시간 : {1})'.format(i, leadTime))

print('총 탑승 승객 : {0} 분'.format(count))

'프로그래밍 > Python' 카테고리의 다른 글

리스트, 딕셔너리, 튜플, 세트  (0) 2022.03.09
문자열  (0) 2022.03.04
연산자  (0) 2022.03.03
자료형  (0) 2022.03.03

BEM

 BEM이란 class 이름을 block, element, modifier로 나눠서 작성하는 것이다.

 

사용법

 block__element--modifier

 위에서 block은 전체적인 container가 된다고 할 수 있는 card이다. 그래서 단순하게 class 이름을 .card라고 해주면 된다.

 

 이 card 안에 들어가 있는 content들, 즉 image, description, button이 elements이다.

 

 이 때 button 사이에 success와 back이라는 2가지 버전(modifier)이 존재한다면 --로 덧붙여주면 된다. 만약 이 button이 해당 card에서 뿐만 아니라 다른 곳에서도 범용적으로 사용된다면 .card__button--success, .card__button--back이라고 하기 보다는 그저 .button--success, .button--back이라고 해주는 것이 재사용성 측면에서 효율적이다.

 

 

 

 이미지 출처 : https://blog.yanis.work/block-element-modifier-bem-css-methodology-df9db9771c6f

'프로그래밍 > CSS' 카테고리의 다른 글

Custom Properties  (0) 2022.03.07

 Data Attribute

 href나 type과 같은 의미가 있는 속성은 아니지만, 해당 요소에 대하여 부가적인 정보를 추가하고 그 부가적인 정보를 통해 그 요소를 지정할 수 있어야 할 때 Data Attribute를 사용한다.

 

기본 사용법

 HTML

<div data-index="1" data-display-name="seung"></div>
<div data-index="2" data-display-name="jun"></div>
<span data-index="1" data-display-name="seung">abcdefu</span>

 추가하고자 하는 데이터 속성은 이처럼 단순히 data- 이후 원하는 데이터 이름을 정해주면 된다.  

 

 CSS

:root {
  --background-color: tomato;
  --margin-bottom: 50px;
}

div {
  width: 200px;
  height: 200px;
  background: var(--background-color);
  margin-bottom: var(--margin-bottom);
}

[data-display-name="seung"] {
  background-color: black;
}

span[data-display-name="seung"] {
  background-color: green;
}

 CSS에서는 위와 같이 []안에 원하는 데이터 속성을 작성하여 해당 요소를 선택할 수 있다.

 

 JavaScript

const seung = document.querySelector("div[data-display-name='seung'"); // 큰 따옴표로 DOM을 선택했다면 값인 seung은 작은 따옴표로 둘러쌓여야 한다.
console.log(seung.dataset); // 출력시 data-가 빠지고 index, displayName(camelCase로 변환됨)이 key값으로 들어간 것을 확인할 수 있다.
console.log(seung.dataset["index"]); // Braket Notation
console.log(seung.dataset.displayName); // Dot Notation

 

 

 dataset으로 해당 요소의 데이터 속성들을 출력해보면 data-가 빠지고 나머지 이름이 key값으로 변하여 객체로 저장된 것을 확인할 수 있다.

 

 이러한 데이터는 민감한 정보를 담고 있을 수 있기 때문에 검사(F12)를 했을 때 안 보이게 할 수도 있어야 한다.

 

 

 

 Data Attribute MDN : https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/Use_data_attributes

'프로그래밍 > HTML' 카테고리의 다른 글

Emmet  (0) 2022.03.06
Semantic Markup, 시멘틱 구조  (0) 2021.11.07

 Custom Properties

.first-list {
  background-color: thistle;
  color: whitesmoke;
  margin-left: 8px;
  --font-size: 32px;
}

.second-list {
  background-color: thistle;
  color: whitesmoke;
  margin-left: 16px;
  font-size: var(--font-size);
}

 위와 같이 계속해서 하드코딩하는 것은 효율적이지 못하다. 코드 양이 방대해질 경우 일일이 수정하기 어렵기 때문이다. 다행히 CSS에서도 이러한 것을 방지하고 재사용성을 높이기 위해 변수를 사용할 수 있다.

 

 기본 사용법

.first-list {
  background-color: thistle;
  color: whitesmoke;
  margin-left: 8px;
  --font-size: 32px;
  /* font-size: var(--font-size); */
}

.first-list li {
  font-size: var(--font-size);
}

.second-list {
  background-color: thistle;
  color: whitesmoke;
  margin-left: 16px;
  font-size: var(--font-size);
}

 변수로 지정되길 원하는 속성에다가 --을 앞에 붙여주면 된다. --font-size과 같이 하면 된다. 그리고 해당 변수를 사용할 때는 var로 가둬줘야 한다. var(--font-size)처럼 말이다. 그리고 CSS 변수는 본인과 자식 요소에게 적용이 된다. 따라서 .second-list에서의 --font-size는 작용하지 않는다.

 

:root {
  --font-size: 32px;
  --background-color: thistle;
  --text-color: whitesmoke;
  /* --base-space: 8px; */
}

.first-list {
  background-color: var(--background-color);
  color: var(--text-color);
  margin-left: var(--base-space ,8px);
  font-size: var(--font-size);
}

.second-list {
  background-color: var(--background-color);
  color: var(--text-color);
  margin-left: calc(var(--base-space) * 2);
  font-size: var(--font-size);
}

@media screen and (max-width: 768px) {
  :root {
    --font-size: 16px;
    --background-color: blue;
    --text-color: white;
    --base-space: 4px;
  }
}

 이렇게 어느 곳에는 적용 되고, 어느 곳에는 적용이 안되는 것을 방지하기 위해 가장 최상위의 요소(root)에다가 CSS 변수를 선언한다.

 

 이제, 변경하고 싶은 style이 있다면 :root에서 수치만 변경하면 된다. 그리고 변수명은 어디에 사용되는 변수인지 직관적으로 알 수 있게 지어줘야 한다.

 

 미디어 쿼리에서도 응용이 가능하다. 화면의 크기가 768px보다 작아지게 되면 해당 CSS 변수가 적용되게 된다.

 

 기본값

.first-list {
  margin-left: var(--base-space, 8px);
}

 만약 해당 변수를 찾을 수 없다면 두 번째 인자로 기본값을 줘서 적용해줄 수도 있다.

 

 

 

 Custom Properties MDN : https://developer.mozilla.org/ko/docs/Web/CSS/Using_CSS_custom_properties

'프로그래밍 > CSS' 카테고리의 다른 글

BEM  (0) 2022.03.07

 보통 HTML파일과 자바스크립트 파일을 따로 만들고, HTML 파일보다 자바스크립트 파일의 용량이 더 무겁다. 자바스크립트 파일을 읽어오는 구문의 위치 혹은 방식에 따라 동작하는 성능이 달라질 수 있다.

 

 script 태그의 위치에 따른 비교

head 태그에 위치하는 경우

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <script src="main.js"></script>
  </head>
  <body></body>
</html>

 head 태그 안에 위치할 경우, js 파일이 엄청 크다면 js 파일을 읽는 데에만 많은 시간이 걸려 HTML을 불러오는 데에 시간이 오래 걸린다.

 

 여기서 Loading JS(혹은 Fetching JS)는 js파일을 서버로부터 받아온다는 것이고, Executing JS는 js 파일을 실행하는 시간이다.

 

body 태그의 맨 밑에 존재하는 경우

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <script src="main.js"></script>
</body>
</html>

 body 태그의 맨 밑에 js 파일을 읽어오는 구문이 존재할 경우이다. HTML을 빠르게 보여줄 순 있겠지만, js 파일 용량이 상당히 크고 js 파일에 따라 HTML의 각 요소들이 변하게 될 경우 정상적인 HTML을 사용자가 보는 데에 시간이 오래 걸리게 된다.

 

 async vs defer

head 태그 안에 있으면서 asyn라는 속성 값을 쓰는 경우

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script async src="main.js"></script>
</head>
<body>
    <div></div>
</body>
</html>

 앞선 경우와 달리 Parsing HTML과 Loading JS가 어느 정도 겹쳐서 일어나기 때문에 시간을 줄일 수 있다. 허나 Parsing HTML과 Loading JS가 겹치기 때문에, 만약 Parsing HTML이 덜 되었는데 js 파일에서 요구하는 HTML 요소가 없는 경우 오류가 생겨 조금 위험할 수 있다.

 

head 태그 안에 있으면서 defer라는 속성 값을 쓰는 경우

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script defer src="main.js"></script>
</head>
<body>
    <div></div>
</body>
</html>

 loading 이후 parsing HTML을 멈추는 동시에 곧바로 executing JS를 하는 async 방식과는 달리, defer의 경우는 parsing HTML을 하다가 script 구문을 만나게 되면 단지 loading JS 명령만 하게 된다. 이후 parsing HTML이 끝나고나면 executing JS가 된다.

 

다수의 js 파일이 존재할 때 async와 defer의 차이

async

 만약 다수의 js 파일이 존재할 경우, async를 사용했다면 loading(fetching)과 executing이 연달아 일어나기 때문에 시간을 절약할 수는 있다. 허나 js 파일이 실행되는 순서가 중요하게 코드가 짜여 있다면 (예로 a -> b -> c로 js 파일이 execute되어야 웹페이지의 기능이 정상적으로 작동한다면) 오류를 범할 수도 있다.

 

defer

 defer의 경우는 parsing HTML을 하다가 script 구문을 만났을 때 병렬로 loading JS를 하게 되고, executing은 script 구문을 만난 순서에 따라 직렬로 진행된다. 따라서 순서가 중요하다면 defer를 썼을 때 async처럼 얽히지 않을 것이다.

 

 따라서 결론적으로는 defer를 사용하는 것이 속도 측면에서(head 안 혹은 body 맨 밑에 위치하는 것과 비교했을 때) 빠르고 오류도 범할 가능성이 낮기 때문에 가장 효율적이다.

 

use strict

 JavaScript는 초기에 아주 급하게 만들어졌고, 상당히 유연한 언어이기 때문에 때때로 개발자의 실수를 허용하기도 한다. 예를 들자면

a = 6;
console.log("hello world");

 위와 같이 코드를 작성해도 "hello world"를 출력한다. JavaScript에서 변수를 선언할 때는 var, let, const를 사용해야 하는데도 말이다. 허나 다음과 같이

"use strict";

a = 6;
console.log("hello world");

 "use strict"를 작성한다면 에러를 발생시킨다. JavaScript에서 기존에 조용히 무시되는 에러들을 출력하기 때문이다. 그래서 다음과 같이

"use strict";

const a = 6;
console.log("hello world");

 "use strict"에서 코드가 작성된다면 에러를 무시할 수 없도록 올바르게 코드를 작성해야 하고 a 변수에는 var이나 let, const가 들어가야 에러를 출력하지 않고 "hello world"가 출력될 것이다.

 

 JavaScript 코드를 작성할 때 이처럼 strict mode를 사용해주는 것이 좋다. 기존에 용인되어 오던 작은 실수들을 에러로 출력하여 코드를 고칠 수 있도록 해주기 때문이다. 이는 좀 더 정확한 JavaScript 코드를 짤 수 있게 해준다. 그리고 작은 실수들은 자바스크립트 엔진이 최적으로 성능을 발휘하는 데에 악영향을 끼치기에 더더욱 strict mode를 사용해주는 것이 좋다.

 

 

 

이미지 출처 : https://betterprogramming.pub/improve-page-load-performance-with-these-different-script-loading-techniques-b0d912eae7b1

유튜브 드림코딩 채널 : https://www.youtube.com/watch?v=tJieVCgGzhs

 

+ Recent posts