11월 

 

알고리즘 재활치료

 

1) 이진탐색

 

백준 10815 : 숫자카드

import sys

N = int(sys.stdin.readline().strip())
lst = list(map(int,sys.stdin.readline().strip().split()))
lst.sort()
M = int(sys.stdin.readline().strip())
mlst = list(map(int,sys.stdin.readline().strip().split()))

for i in range(M): #M번의 이진탐색 
    start = 0 
    last = N-1
    c = 0
    while(start <= last):
        c = int((start + last) / 2)
        if mlst[i] < lst[c]:
            last = c - 1
        elif mlst[i] == lst[c]:
            break
        else:
            start = c + 1
            
    if mlst[i] == lst[c]: #찾은 수가 mlst 안에 있을 시
        print("1", end=" ")
    else:
        print("0", end=" ")

이진탐색 알고리즘의 반복문의 조건이 while (start <= last) 라는 것을 잊지말자

 

2) 백트래킹

 

백준 15666: N과M (12)

#백트래킹
import sys

n,m = map(int,sys.stdin.readline().strip().split())
lst = set(map(int,sys.stdin.readline().strip().split()))
num = list(lst)
num.sort()
stack = []

def back():
    l = len(stack)
    if l == m:
        print(" ".join(map(str,stack)))
        return
    else:   
        for i in range(len(num)):
            if l == 0 or num[i] >= stack[-1]:
                stack.append(num[i])
                back()
                stack.pop()
            
back()

스택 자료구조를 사용하면 좀 더 쉽게 구현가능하다

 

3) DFS,BFS

 

BFS  - 백준 2206 : 벽 부수고 이동하기

# BFS
import sys,copy
from collections import deque

n,m = map(int,sys.stdin.readline().strip().split())
lst = [[0]*n for _ in range(2)]
maplst = [0]*n

for i in range(n):
    maplst[i] = list(map(int,sys.stdin.readline().strip()))
    lst[0][i] = copy.deepcopy(maplst[i])
    lst[1][i] = copy.deepcopy(maplst[i])
    
dx = [1,-1,0,0]
dy = [0,0,1,-1]
      
dq = deque()
dq.append((0,0,0))

lst[0][0][0] = 1
lst[1][0][0] = 1

while dq:
    x,y,c = dq.popleft()
    for i in range(4):
        nx,ny = x+dx[i],y+dy[i]
        
        if nx < m and nx >= 0 and ny < n and ny >= 0:
            if c == 0: # 한 번도 벽 부순적 없을 때
                if maplst[ny][nx] == 0 and lst[0][ny][nx] == 0:
                    lst[0][ny][nx] = lst[0][y][x] + 1
                    dq.append((nx,ny,0))
                    #lst[1][ny][nx] = lst[0][y][x] + 1
                elif lst[1][ny][nx] == 1:
                    lst[1][ny][nx] = lst[0][y][x] + 1
                    dq.append((nx,ny,1))
            else: # 벽 이미 한 번 부순 후
                if maplst[ny][nx] == 0 and lst[1][ny][nx] == 0:
                    lst[1][ny][nx] = lst[1][y][x] + 1
                    dq.append((nx,ny,1))
                    
      
a = lst[0][n-1][m-1]
b = lst[1][n-1][m-1]

if a == 0 and b == 0:
    print(-1)
elif a == 0 and b != 0:
    print(b)
elif a != 0 and b == 0:
    print(a)
else:
    print(min(a,b))

BFS는 큐를 이용하면 구현이 편해진다

 

4) DP

 

백준 12865 : 평범한 배낭

# DP 이용 배낭문제 풀이
import sys

n,k = map(int,sys.stdin.readline().strip().split())
lst = []

for i in range(n):
    lst.append(list(map(int,sys.stdin.readline().strip().split())))

lst.sort()

dp = [[0]*(k+1) for _ in range(n)]

for i in range(n):
    w,v = lst[i][0],lst[i][1]
    for j in range(1,k+1):
        if j-w >= 0:
            if i == 0:
                dp[i][j] = v
            else:
                dp[i][j] = max(v,dp[i-1][j-w] + v,dp[i-1][j])
        else:
            if i > 0:
                dp[i][j] = dp[i-1][j]
                
print(dp[-1][-1])

사실 어떻게 풀었는지 기억이 잘 안난다

 

5) 구현

 

백준 26006 : K-Queen

import sys

n,k = map(int,sys.stdin.readline().strip().split())
queen = []
check = [False]*9
king_y,king_x = map(int,sys.stdin.readline().strip().split())
king = [[0,0],[1,0],[-1,0],[0,1],[0,-1],[1,1],[1,-1],[-1,1],[-1,-1]]

for i in range(9):
    king[i][0] += king_x
    king[i][1] += king_y
    
for i in range(k):
    y,x = map(int,sys.stdin.readline().strip().split())
    queen.append([x,y])
    
for i in range(9):
    king_x,king_y = king[i][0],king[i][1]
    if king_x <= 0 or king_y <= 0 or king_x > n or king_y > n:
        check[i] = True
    else:
        for j in range(len(queen)):
            queen_x,queen_y = queen[j][0],queen[j][1]
            
            if king_x == queen_x or king_y == queen_y:
                check[i] = True
            elif king_x - king_y == queen_x - queen_y or king_x + king_y == queen_x + queen_y:
                check[i] = True
    
if check[0] == 1:
    if 0 in check:
        print('CHECK')
    else:
        print('CHECKMATE')
else:
    if check.count(0) == 1:
        print('STALEMATE')
    else:
        print('NONE')

홍익대학교 프로그래밍 경진대회 오픈 콘테스트 문제였다.

이걸 구현하는데 시간이 너무 오래 걸려서 다른 문제도 못 풀었다.

체스판을 탐색하는 알고리즘은 그냥 외워두는게 좋을 것 같다.

프로젝트를 진행하던 도중 json안에 json을 넣는 등 복잡한 구조의 통신이 필요해졌다.

 

칵테일 레시피를 보여주는 웹사이트를 제작 중이다.

칵테일 레시피가 데이터 베이스에 저장되는 방식은 이렇다.

 

1. 칵테일 이름

2. 베이스 (술 이름, 들어가는 양(oz))

3. 서브 (재료 이름, 들어가는 양)

4. 부재료 (재료 이름, 들어가는 양)

5. 조합법

 

일단은 1,2,3 만 구현해보기로 했는데

결론적으로 다음과 같은 JSON을 보내야 한다.

베이스 재료와 서브 재료는 각각 들어가는 재료 이름과 양을 모두 가지고 있어야해서 하나의 json으로 만들었다.

즉 json 안에 json을 넣어 통신을 해야하는 상황인데 지금까지 배운 serializer의 기본 사용법으로는 구현하는데 한계를 느꼈다.

 

 

그러던 도중 발견한 것이 장고의 외래키(ForeignKey)기능이다.

외래키 기능은 장고에서 모델을 만들때 두개 이상의 모델을 연결할 수 있도록 하는 기능이다.

 

외래키 사용법을 검색했을때 공식 문서에서는 앨범과 앨범 수록곡(track) 모델을 연결하는 것을 예시로 들어주었다.

 

공식문서

https://www.django-rest-framework.org/api-guide/relations/#api-reference

 

Serializer relations - Django REST framework

relations.py Data structures, not algorithms, are central to programming. — Rob Pike Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as to reverse re

www.django-rest-framework.org

번역본?

https://kimdoky.github.io/django/2018/07/13/drf-Serializerrelations/

 

Django REST Framework - Serializer relations

on July 13, 2018 under django 22 minute read Django REST framework - Serializer relations “Bad programmers worry about the code. Good programmers worry about data structures and their relationships.” “나쁜 프로그래머는 코드에 대해 걱정

kimdoky.github.io

 

그래서 저 자료를 활용해서 model 클래스와 serializer을 작성해봤다.

 

베이스 재료들과 서브 재료들이 모여있는 BaseIngredient, SubIngredient 모델 클래스를 만들고

외래키를 이용해 CocktailIngredient 클래스에 연결했다.

#models.py
from django.db import models


class CocktailIngredient(models.Model):
    cocktail_name = models.CharField(max_length = 100, primary_key="True")
class BaseIngredient(models.Model):
    cocktail_name = models.ForeignKey(CocktailIngredient, related_name="base_ingredients",on_delete=models.CASCADE,db_column="base")
    drink_name = models.CharField(max_length=100,default="")
    oz = models.FloatField(default=0.0)

    # def __str__(self):  
    #     return f'{self.drink_name}: {self.oz} oz'
class SubIngredient(models.Model):
    cocktail_name = models.ForeignKey(CocktailIngredient, related_name="sub_ingredients",on_delete=models.CASCADE,db_column="sub")
    drink_name = models.CharField(max_length=100,default="")
    oz = models.FloatField(default=0.0)

    def __str__(self):
        return f'{self.drink_name}: {self.oz} oz'

그리고 serializer을 구성하는 방법은 여러가지가 존재하는데

StringRelatedField

slugRelatedField

등등..

아래 예시에선 Nested relationships 방법을 사용하기로 했다.

#serializers.py
from rest_framework import serializers
from .models import BaseIngredient, CocktailIngredient, SubIngredient

class BaseIngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = BaseIngredient
        fields = ('drink_name','oz')

class SubIngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = SubIngredient
        fields = ('drink_name','oz')

class CocktailIngredientSerializer(serializers.ModelSerializer):
    #base_ingredients = serializers.StringRelatedField(many=True, read_only = True)
    #sub_ingredients = serializers.StringRelatedField(many=True, read_only=True)
    base_ingredients = BaseIngredientSerializer(many=True)
    sub_ingredients = SubIngredientSerializer(many=True)
    
    class Meta:
        model = CocktailIngredient
        fields = ('cocktail_name','base_ingredients','sub_ingredients')

    def create(self, validated_data):
        base_data = validated_data.pop('base_ingredients')
        sub_data = validated_data.pop('sub_ingredients')
        cocktail = CocktailIngredient.objects.create(**validated_data)
        for base in base_data:
            BaseIngredient.objects.create(cocktail_name=cocktail,**base)
        for sub in sub_data:
            SubIngredient.objects.create(cocktail_name=cocktail, **sub)

        return cocktail

말 그래도 serializer을 중첩해서 사용하는데 이 경우 create 함수를 따로 만들어줘야한다.

사실 예재에 있는거 그대로 따라했는데 create 함수 부분은 아직 완벽히 이해가 안된다.

 

 

더 공부 후 추가 예정

개발환경

Mac + Visual Studio Code + Python 3.10.5

 

django REST framework를 사용해 구현할 때 핵심은 Serializer 이다.

django 내부의 복잡한 로직을 Serializer가 간단하게 구현해준다.

 

 

백엔드 API를 구현할 때 구현한 서버는 사용자와 정보를 주고 받아야 하고 정보를 주고 받을때 사용되는 통일된 규칙을 JSON이라고 한다.

백엔드 서버는 사용자로 부터 요청을 받으면 데이터베이스에서 정보를 꺼내와 JSON형태로 프론트엔드로 건내주거나

혹은 사용자로부터 JSON을 받아 데이터베이스에 추가하는 식으로 작동한다.

 

장고에서 데이터베이스에 접근하고 관리할 때에는 model이라는 클래스를 만들어 사용한다.

model 클래스와 메소드 덕분에 따로 SQL문을 배우지 않아도 장고는 데이터베이스를 쉽게 관리할 수 있다.

 

그리고 Serializer은 model 클래스와 JSON을 연결해주는 도구라고 생각하면 될 것 같다.

JSON -> model로 혹은 반대인 model-> JSON으로 변경을 쉽게 할 수 있도록 해준다.

 

 

Serializer 사용법

1. 생성

Serializer 생성을 위해선 우선 데이터베이스를 관리할 model 클래스부터만들어야 한다.

앱 파일의 models.py 에서 간단한 예시를 만들어 봤다. (모델 생성후 migration을 잊지 말자)

from django.db import models

class Student(models.Model):
	name = models.CharField(max_length=20)
    number = models.CharField(max_length=30)
    grade = models.IntegerField(default = 1)

 

생성을 하고 간단하게 사용하기 위해선 장고 앱 파일 속에 serializers.py 라는 파일을 생성하고 내용을 작성한다.

from rest_framework import serializers
from app.models import Student

class StudentSerializer(serialiers.Serializer):
	class Meta:
    	model = Student
        fields = ['name', 'number', 'grade']

 

2. 사용

이렇게 생성된 Serializer 은 아까 말했던 것 처럼 크게 두 가지의 일을 수행할 수 있다.

첫번째는 사용자에게 JSON을 받아와 model 클래스(Student)로 바꿔 데이터 베이스를 관리

두번째는 데이터 베이스의 정보인 Student를 JSON으로 바꿔 사용자에게 전송

 

이 과정은 views.py에서 이루어진다.

 

1) 사용자 -> 서버

data = JSONParser().parse(request)
serializer = StudentSerializer(data = data)
serializer.save()

 2)서버 -> 사용자

obj = Student.object.get(name = 'kim') #이름이 kim인 Student
serializer = StudentSerializer(obj)
JsonResponse(serializer.data, option)

3) 수정 및 삭제

#수정
obj = Student.object.get(name='kim')
data = JSONParser().parse(request)
serializer = StudentSerializer(obj, data = data)
serializer.save()

#삭제
obj = Student.object.get(name='kim')
obj.delete()

 

 

3. 사용 예시

 

urls.py(프로젝트 파일)

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('app.urls')), #앱 파일의 urls.py에 연결
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

 

urls.py (앱 파일)

from django.urls import path
from . import views

urlpatterns = [
    path('students',views.student_list), #학생 목록 읽기, 학생 추가
    path('students/<int:pk>',views.student) #개별 학생 목록 읽기, 수정, 삭제
]

 

 

views.py

from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from app.models import Student 	# 앱파일의 models.py
from app.serializers import StudentSerializer # 앱 파일의 serializesr.py

# Create your views here.

@csrf_exempt
def student_list(request):
    if request.method == 'GET': # 학생 목록 읽기
        query_set = Student.objects.all()
        serializer = StudentSerializer(query_set,many = True)
        return JsonResponse(serializer.data, safe = False)

    elif request.method == 'POST': # 학생 새로 추가
        data = JSONParser().parse(request)
        serializer = StudentSerializer(data = data)
        if serializer.is_valid(): #serializer
            serializer.save()
            return JsonResponse(serializer.data, status=200)
        else:
            return JsonResponse(serializer.error, status=400)

@csrf_exempt
def student(request,pk):
    if request.method == 'GET':
        obj = Student.objects.get(pk = pk)
        serializer = StudentSerializer(obj)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'PUT':
        obj = Student.objects.get(pk = pk)
        data = JSONParser().parse(request)
        serializer = StudentSerializer(obj,data = data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=200)
        else:
            return JsonResponse(serializer.error, status=400)

    elif request.method == 'DELETE':
        obj = Student.objects.get(pk=pk)
        obj.delete()
        return HttpResponse(200)

사용 예시에서 설명을 안 했던 부분을 간단하게 짚자면

@csrf_exempt는 사용자가 마음대로 데이터베이스에 접근하는 것을 막기 위한 csrf 보안을 무시하는 명령어로

POST, PUT 메소드를 사용하는 함수 앞에 붙여서 사용해야한다.(없으면 오류가 생긴다)

 

 

serializer.is_valid()는 serializer.save()를 사용하기 전에 반드시 확인해봐야 한다고

공식 문서에 나와있는데 사실 왜 하는지는 아직 잘 모르겠다.

더 공부 해봐야겠다.

 

 

저렇게 코드를 구성한 후 'Insomnia'를 이용해 JSON을 전송해보면 제대로 작동해서

HTTP 메소드(GET, POST, PUT, DELETE)와 JSON을 이용해 데이터베이스를 관리하는 아주 간단한 REST API가 만들어졌다.

 

이번 연습 프로젝트는 https://grape-blog.tistory.com/14?category=473970 이 블로그를 참고했고

Insomnia 에 대한 자세한 사용법도 알려주고 있다.

REST API 를 장고를 이용해 구현하는 것이 이번 프로젝트의 목표다.

 

장고 개발을 위한 가상환경 설정 방법 및 장고 웹 어플리케이션의 동작 방법에 대해 이미 간단히 알고 있다고 가정하고 글을 쓰겠다.

잘 모르겠다면 온라인 무료 강의 및 공식문서 튜토리얼을 통해 익히고 오는 것을 추천한다.

 

(나는 1. Do it! 점프 투 장고, 2. 유튜브 생활코딩 장고 강의, 3. 공식문서 튜토리얼을 진행해봤다.  

난이도는 1> 3 >>>>> 2 이지만 2번은 정말 간단하게만 짚고 넘어가므로 2번으로 감을 잡고 1,3을 진행해보는 것을 추천한다.)

 

 

장고에서 REST API 개발을 할 때 유용한 REST framework 가 있다.

django REST framework 인데, 본 프로젝트 시작 전 아주 간단한 연습 프로젝트를 해보려고 한다.

pip install djangorestframework
pip install markdown
pip install django-filter

터미널을 열고 본인의 장고 프로젝트를 진행할 가상환경에 접속한 뒤 위의 명령어를 입력해 다운로드하자.

 

python manage.py startproject "projectName"
python manage.py startapp "appName"

그 이후 장고 위의 명령어를 이용해 프로젝트와 앱을 생성한후 몇개의 파일을 수정해야한다.

 

우선 메인 프로젝트 파일의 settings.py 로 이동해 앱 이름과 프레임워크 이름을 추가해줘야한다.

아무생각 없이 연습용 프로젝트 이름을 restApi, 앱 이름을 그냥 api 라고 지었는데 좋지 않은 이름이다.

 

settings.py 의 INSTALLED_APPS 로 가서 'rest_framework', 와 앱 이름을 추가하면 된다.

그리고 나서 settings.py의 맨 아래로 내려가 다음과 같은 코드를 추가해준다.

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}

 

그 후 settings.py와 같은 프로젝트 폴더에 위치한(앱 파일이 아니다) urls.py에 들어가 빨간 밑줄 그은 코드를 추가해준다.

이렇게 하면 기본 세팅은 끝난다.

 

여기서 원한다면 데이터베이스를 연결하고, 깃허브 레포지토리에 연결하는 등 과정이 있지만

선택사항이고 간단한 연습 프로젝트이므로 여기선 생략하도록 하겠다.

 

 

또 API 서버 테스트를 위해 서버로 데이터를 전송해주는 프론트엔드의 역할을 대신해주는 클라이언트를 사용해보기로 했다.

"isomnia" 인데 구글에 검색하면 무료로 다운받을 수 있다.

 

마무리하기 전 migration을 진행해 기본 데이터베이스를 만들고 runserver 명령어까지 잘 실행되는지 확인하자.

 

연습 프로젝트는 https://grape-blog.tistory.com/13?category=473970를  참고했다.

 

 

API 란?

Application Programming Interface

어플리케이션이 어떤 프로그램이 제공하는 기능을 사용할 수 있도록 연결하는 매개체

라고 하는데 잘 이해가 안된다.

 

대충 프로그램과 프로그램을 연결하는 통로 라고 이해하라는 글을 발견했다.

 

API는 프로그램과 프로그램을 이어주는 매개체 그 자체의 의미를 가진 것이기 때문에 API의 정의와 가장 가까운 개념은 "연결 통로"라고 보면 되구요. 

그렇다면 '네이버 맵 API'라는 API가 있다고 가정 했을 때, 위 설명대로면 이 문장이 어색하고 부족해보일 수 있는데요.
이 문장을 풀어보면 "네이버 서버(PC)에 있는 맵 기능을 다른 사용자들이 사용할 수 있게 만든 API(통로)"가 되는 것이고 

"네이버에서 맵 API를 제공한다." 라는 말은 "API(통로)를 통해 네이버의 맵 기능을 여러 사람이 사용할 수 있게 프로그래밍하여 제공한다"는 뜻이 되는 겁니다.

https://dev-dain.tistory.com/50

 

HTTP API란?

 

HTTP(HyperText Transfer Protocol)란?

HTML과 같은 하이퍼미디어 문서를 전송하는 프로토콜

웹 브라우저와 서버와의 통신을 위해 사용된다.

클라이언트(브라우저) -> 서버로 요청(request) 후에 서버가 다시 브라우저로 응답(response) 하는 방식으로 진행된다.

request 는 GET,POST,DELETE,PUT,FATCH 등과 같은 HTTP 메소드를 이용해 이루어진다.

 

HTTP API 는 HTTP표준 접근 방식을 사용해 프로그램끼리 소통하는 API를 이야기한다.

 

 

 

REST API 란?

 

REST(Representational State Transfer) 원칙에 따라 구현한 API 이다.

REST는 HTTP를 잘 활용하기 위한 원칙이고, REST API는 이 원칙을 준수하여 만든 API이다.

 

REST는 url로 자원을 표현하는데 집중하고 자원을 활용할 행위는 HTTP 메소드를 사용하여 실행하는 것을 주요 원칙으로 한다.

/create_student
/get_student/kim
/update_student/kim
/delete_student/kim
/get_students

이러한 url이 존재한다고 하자. url만으로 무슨 기능을 수행하는지는 알겠지만 REST 규칙에 맞는다고 할 수 없다.

REST를 제대로 적용한 url은 자원만을 표현한다. 즉 명사로 이루어져야한다.

 

/student	#create
/student/kim	#read
/student/kim	#update
/student/kim	#delete
/students	#read

위의 url에서 동사를 모두 지우고 명사만 남겨봤다.

이렇게 url을 작성한다면 겹치는 url이 생기고 한 개의 url이 연결하는 페이지가 여러가지 기능을 수행할 수 있어야 한다.

이때 사용해야 할 것이 HTTP 메소드이다.

 

GET = read

POST = create

PUT = update

DELETE = delete

 

이 4가지의 HTTP 메소드를 사용해 CRUD 기능을 구현한다.

/students	
/students/kim

결론적으론 이렇게 두 개의 url만 만들어 놓은후

/students url에서 GET 메소드 요청시 학생 정보 출력, POST 메소드 요청시 새로운 학생 생성

/students/kim 에서 PUT 메소드 요청시 학생 정보 수정, DELETE 메소드 요청시 학생 정보 삭제

의 기능을 모두 수행할 수 있다.

 

 

장고로 REST API 구현하기

장고로 백엔드 rest api를 구현하기 위해 만들어진 djangorestframework 가 존재했고 이걸 사용해볼 예정이다.

간단하게 설명하자면 http 요청과 JSON이 전송됐을 때 위의 프레임워크를 사용하면

serializers라는 기능을 사용해 아주 쉽고 빠르게 JSON<-> 데이터베이스 쿼리셋 변환이 가능하다.

 

자세한 실습 과정은 다음 글에 이어서 쓰도록 하겠다.

실습 과정은 https://grape-blog.tistory.com/16?category=473970 를 참고했다.

드림코딩 JS강의를 들으며 공부하던 중

3강, 4강에서 이상한 점을 발견해서 정리하려고 한다.

 

 

Boolean 자료형을 배우던 중

0, null, undefined, NaN,  '' 이 false로 판정된다는 이야기를 봤다.

 

 

그리고 VS code를 키고

 

아래와 같이 입력한 후 콘솔 창을 확인했더니

이상한 결과가 나왔다.

console.log(false == 0);  // true
console.log(false == ''); // true
console.log(false == null); // false
console.log(false == undefined); // false
console.log(false == NaN); // false
console.log(false == []); // true

 

왜 null, undefined NaN은 false와 == 연산자에서 true가 나오지 않는걸까

또 [] 는 false와 == 연산자에서 true가 나오는데 왜 위에 수업에서 이야기하지 않았을까

 

 

'use strict'

console.log(null == undefined); //true
console.log(null == NaN); //false
console.log(undefined == NaN); //false

또 다음 입력 테스트는 이런 결과가 나왔다.

null 과 undefined 끼리의 비교는 true

NaN과의 비교는 false로 나왔다.

 

 

 

 

1. Boolean, if 연산자에서의 false 취급

 

영상에서 말한 false와 같다는 이야기는 비교 연산자 == 가 아닌

Boolean 연산자에서 false 취급을 받는다는 이야기였다.

if (undefined){
    console.log('true');
}
else {
    console.log('false');
}

즉 다음과 같은 식에서 undefined는 false로 취급을 받아 콘솔에 'false' 를 출력하게 된다.

Boolean(undefined) 역시 false를 반환한다.

 

 

if ([]){
    console.log('true');
}
else {
    console.log('false');
}

그래서 이 코드에선 [] 가 true로 취급을 받아 콘솔에 'true'를 출력했다.

 

 

 

2. undefined, null, NaN의 타입 비교

 

// undefined & null 타입 비교
// undefined 대신 null 대입해도 동일한 결과 반환

undefined == undefined // true
undefined == 0 // false
undefined == false // false
undefined == null // true
undefined == '' // false
undefined == NaN // false
undefined == [] // false


// NaN 타입 비교

NaN == NaN // false
NaN == 0 // false
NaN == false // false
NaN == null// false
NaN == undefined // false
NaN == '' // false
NaN == [] // false

 

 

3. undefined 와 null의 차이점

 

let a;
console.log(a); // undefined 출력

let b = null;
console.log(b); // null 출력

a == b // true
a === b // false

 

undefined는 선언된 변수에 아직 아무 값을 넣지 않았을때 나온다.

즉 C, C++의 쓰레기 값과 같다.

 

다음과 같은 상황에서 undefined 자료형이 반환된다.

  • 값을 할당하지 않은 변수
  • 메서드와 선언에서 변수가 할당받지 않은 경우
  • 함수가 값을 return 하지 않았을 때

 

null은 존재하지 않는 값 또는 유효하지 않은 주소 혹은 object를 가리키는 참조이다.

C, C++ 의 NULL과 같다.

 

즉 변수 값이 null임은 변수의 선언 후 초기화 까지 된 상황이고

undefined 는 초기화 되지 않음을 의미한다.

 

물론 a = undefined; 라는 식으로 초기화 할 수 있지만

추천하지 않는 방법이고

변수의 초기화는 null을 이용하는 것이 좋다.

 

그리고 변수를 비교할때는 그냥 === 비교 연산자를 사용하자.

 

 

 

 

 

 

 

 

 

본격적인 장고 스터디에 앞서

장고 및 html,css,js 공부를 vs code를 이용해 공부하기로 했고

mac 노트북에서도 vs code 를 사용할 일이 많아질 것 같아 

mac용 vs code 단축키를 정리하려고 한다.

 

기호 의미

option

command

shift

 

control

 

가장 자주 쓰이는 단축키들

기호 기능

⌘ + ↑,↓

커서 문서 맨 위나 맨 아래로 이동

⌘ + ←,→

커서 지금 가리키는 문장 맨 앞이나 뒤로 이동

⇧ + ↑,↓

커서 위, 아래로 드래그

  + K

커서 있는 위치부터 오른쪽 끝까지 삭제

⇧ + ⌥ + ↑↓

 

현재 줄 복사, 붙여넣기

⌥ + ↑↓

현재 줄 위치 바꾸기

⌘ + D

 

문서 내의 동일한 문자들 드래그

 

추후 업데이트 예정

남들 다 하길래 시작하는 블로그

주된 글은 포트폴리오, 개발일지 및 정보공유... 였으면 좋겠지만 일기장이나 낙서장이 될 것 같은 느낌

아니 일기라도 열심히 쓰면 다행이지

작년에 쓰던 블로그는 3일만에 없어졌는데 이건 얼마나 오래갈까

허허

 

블로그 제목 '계란으로 바위치기'는 내 코딩 공부 방법을 제일 잘 나타내는 말인것 같아서 저렇게 지었다.

나는 지금까지 코딩 공부를 냅다 대가리부터 박으면서 했다  실습 위주로 진행했다.

백준을 풀때도 일단 생각나는데로 구현해보고 방구석 무한도전을 찍은 후에 정 안풀리면 알고리즘을 구글링 해봤다.

HTML CSS도 기본적인 강의만 듣고 클론코딩부터 진행했고 현재 공부중인 장고도 마찬가지이다.

 

나는 앞으로 이 블로그에 내가 계란으로 바위를 치면서 겪은 시행착오와 발전하는 과정을 적어내려고 한다.

바위 아니면 내 머리 둘 중 하나는 깨지겠지 뭐

 

 

 

 

 

+ Recent posts