[모던 자바스크립트 Deep Dive] 스코프
식별자(변수, 함수, 클래스 등)는 선언된 위치에 따라 유효 범위가 결정되는데, 이를 스코프라고 한다. 자바스크립트는 함수 몸체나 모든 코드 블록이 지역 스코프를 만들며, var 키워드로 선언된 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정한다. let과 const 키워드는 블록 레벨 스코프를 지원하며, 함수의 상위 스코프는 정적으로 결정된다.
0개의 댓글
0개의 질문
dongree
안녕하세요. FE개발자를 희망하는 dongree입니다!
식별자(변수, 함수, 클래스 등)는 선언된 위치에 따라 유효 범위가 결정되는데, 이를 스코프라고 한다. 자바스크립트는 함수 몸체나 모든 코드 블록이 지역 스코프를 만들며, var 키워드로 선언된 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정한다. let과 const 키워드는 블록 레벨 스코프를 지원하며, 함수의 상위 스코프는 정적으로 결정된다.
0개의 댓글
0개의 질문
리액트는 사용자 인터페이스를 구축하기 위한 선언적인 자바스크립트 라이브러리로, 컴포넌트 기반 아키텍처와 가상 DOM을 통해 재사용 가능한 UI를 만들고 성능을 향상시킬 수 있습니다. 리액트의 특징으로는 단방향 데이터 흐름과 JSX를 사용한 선언적 UI 작성 등이 있으며, 이는 예측 가능하면서도 효율적인 애플리케이션 개발을 도와줍니다.
0개의 댓글
0개의 질문
JPA의 영속성 관리는 영속성 컨텍스트라는 환경에서 엔티티를 영구 저장하는 것을 의미합니다. 영속 엔티티의 동일성은 보장되고, 변경 감지와 쓰기 지연 등 여러 기능을 통해 효율적인 데이터베이스 연산이 가능합니다.
1개의 댓글
1개의 질문
CSS는 Cascading StyleSheet의 약자로, HTML 문서의 스타일을 꾸밀 때 사용하는 스타일시트 언어입니다. 글꼴, 배경색, 넓이, 높이, 위치 등을 지정하여 웹 브라우저나 스크린 크기에 따라 화면을 다르게 표시할 수 있도록 합니다.
0개의 댓글
0개의 질문
HTML은 웹 문서를 만들기 위해 사용되는 마크업 언어로, 웹페이지의 구조를 브라우저가 인식할 수 있도록 하는 역할을 합니다. 여러 종류의 태그를 사용하여 텍스트, 링크, 이미지 등을 표현하고 조작할 수 있습니다. HTML은 기본적으로 여는 태그, 닫는 태그, 내용으로 구성되며, 블록태그와 인라인태그로 나눌 수 있습니다.
0개의 댓글
0개의 질문
리액트 쿼리는 리액트 애플리케이션에서 데이터를 가져오고 캐시하는 데 도움을 주는 라이브러리입니다. 예시 코드를 통해 간단하게 서버로부터 데이터를 요청하고 이를 컴포넌트에서 사용할 수 있습니다.
0개의 댓글
0개의 질문
slice() 메소드는 원본 배열을 변경하지 않고, start부터 end 앞 인덱스까지의 배열을 반환합니다. 반면에 splice() 메소드는 원본 배열을 변경하며, start로부터 n개의 원소를 삭제합니다.
0개의 댓글
0개의 질문
참조 무결성은 유효한 데이터만 테이블에 삽입되도록 보장하며, 외래 키를 사용하여 다른 테이블의 기본 키와 관련된 열을 제약 조건으로 설정한다. 인덱스는 데이터를 정렬하여 검색과 정렬 작업 속도를 높이는데 사용되지만, 저장 공간을 많이 차지하고 데이터 필터링과 정렬에만 유용하다. 트리거는 데이터베이스 작업 발생 시 자동으로 수행되며, 일관성 보장과 추가적인 데이터 유효성 검사 등의 용도로 사용된다. DBMS는 보안 처리를 위해 데이터 접근 권한을 부여하거나 제재하는 매커니즘을 가지고 있다. 계단식 삭제와 사용자 정의 데이터형은 일부 DBMS에서 지원하는 기능으로 각각 관련된 모든 행을 삭제하는 기능과 재사용 가능한 제약 조건 및 체크 무결성 제약 조건을 추가할 수 있는 기능이다.
0개의 댓글
0개의 질문
SWEA - 햄버거 다이어트(5215)에서는 조합을 사용하여 제한 칼로리 내에서 최대 맛에 대한 점수를 구하는 문제를 해결하는 코드입니다. 주어진 재료의 수와 제한 칼로리를 변수로 받아오고, 각 재료의 맛에 대한 점수와 칼로리를 리스트에 할당합니다. 그 후, 조합을 이용하여 가능한 모든 경우의 수를 계산하고 최대 점수를 구합니다.
1개의 댓글
0개의 질문
memo memo 자동생성 AI기반의 글쓰기 도우미입니다. 이전 텍스트를 기반으로 문맥을 파악하여 완전한 문장을 작성합니다. 어떤 내용에 대해 도움이 필요하신가요?
0개의 댓글
0개의 질문
Inforum은 생성형 AI를 활용하여 텍스트 자동 생성, 태그 및 요약 기능을 제공합니다. 또한 메모를 통합하여 시리즈로 출간하고, 기술 포스트와 연동된 질문/답변 기능도 제공됩니다. 등급제와 Post History를 통해 동기부여도 가능합니다.
0개의 댓글
0개의 질문
기술블로그를 쓸 생각을 했지만 실천하지 못했다면, Inforum이라는 웹서비스를 소개합니다. Inforum은 기술 질문과 답변 커뮤니티로, 간편하고 편리하게 사용할 수 있습니다. 현재 회원가입 후 글 작성과 설문조사 참여 시 네이버페이 3000원 지급 이벤트도 진행 중입니다.
1개의 댓글
0개의 질문
리액트 쿼리에서는 api 응답 값으로 에러를 반환하더라도 onError에 적어놓은 에러 처리가 되지 않는 오류가 발생합니다. 이를 해결하기 위해서는 api fetch하는 코드에서 발생한 에러를 throw 해야 onError에서 잡을 수 있습니다.
0개의 댓글
0개의 질문
기존에는 execCommand 라는 함수가 사용되었으나 deprecate되면서 Clipboard API를 권장하게 되었다. navigator.clipboard.writeText() 위 메서드의 parameter로 복사할 값을 넣으면 된다. 만약 복사에 성공하면 toast를 띄우는 등의 동작을 하고 싶다면 then으로 연결하면 된다. navigator.clipboard.writeText(\"\").then(() => 동작) 주의! localhost 가 아닌 http 환경에서는 동작하지 않는다. (에러가 발생한다)
0개의 댓글
0개의 질문
(스크린샷은 향후 추가 예정) (틀린 점, 궁금한 점은 적극적으로 공유해주셔도 좋습니다!) 개발자분들이 늘 고민을 많이 하시는 부분이 개발 환경이라고 저는 종종 생각합니다. 그렇기에 개발 환경은 개발자들에게 항상 중요한 고민거리입니다. 저 역시 최대한 다양한 환경을 테스트해보고 내가 사용하기 좋은 환경일지 고민해보죠. 이 과정에서 새로이 쓰게 된 개발환경이 바로 Neovim과 NvChad 입니다. Vim? Neovim? Vim은 우리가 모두 들어봤을 거 같은데요, 대부분의 Linux/Unix 환경에 탑재되어 있는 친구가 바로 Vim입니다. 잘 쓰는 분들은 Vim으로 날라다니시지만, 저는 그러지 못해서, Neovim을 알기 전까지는 제대로 써보지 못했습니다. Neovim은 여러분이 잘 아시는 그 Vim에 확장성, 좀 더 향상된 UI 등을 접목한 Vim의 후예같은 친구입니다. Vim도 plugin 등을 적용할 수 있지만 Neovim은 더 사용하기 편안하도록 VSCode와 유사한 UI, Launguage Server Support 등을 지원합니다. 기존의 내장 기능만을 사용하는 Vim과는 어느정도 차이가 있죠. 왜 Vim? Vim을 선택한 건 갑작스러운 변덕이라기보다는, 하나의 불행에서 시작되었습니다. (제게는) VSCode의 필수 extension인 Remote-SSH가 먹통이 되었거든요. 물론 그 버그는 금방 해결되었습니다만... 하루를 생으로 날려보낼 수는 없던 제 입장에서는 이런 상황이 생길 때를 대비한 backup이 필요했고 그 과정에서 가볍지만 원하는 기능을 모두 제공하는 Vim을 사용해봤습니다. 다만 Vim만을 사용하지는 않았죠. NvChad? 앞에서 언급드렸다시피 Neovim은 확장성, 향상된 UI 등을 제공합니다. 하지만 Vim 초심자에게 있어 Neovim의 설정을 바로 하기에는 좀 (많이) 어렵습니다. 그래서, 초심자들을 위한 plugin과 설정의 집합?과 같은 녀석들이 등장했죠. NvChad, LunarVim 과 같은 친구들이 그 친구들이죠. (얼마나 꾸준히 작성할지는 잘 모르겠지만) 밑밥을 열심히 깔아 두었으니 이제부터 조금씩 설정하면서 삽질한 이야기들을 해보려고 합니다. 두서없는 글 봐주셔서 감사하고 만약 계속 따라오실 예정이시라면 앞으로 잘 부탁드립니다. Reference. https://github.com/NvChad/NvChad https://github.com/neovim/neovim
1개의 댓글
0개의 질문
1. Soft Delete Soft Delete란 soft delete는 database 의 테이블에서 물리적으로 데이터를 삭제하는 대신 마킹을 통해서 delete 를 구현하는 방식이다. soft delete를 구현하는 가장 보편화된 방식은 삭제여부를 나타내는 field 를 추가하는 방식이다. 다음은 deleted 란 field 를 통해 삭제 여부를 관리하는 방식의 예시이다. Soft Delete 수행법 해당 테이블에서 다음과 같은 SQL command를 통해 delete 작업을 수행할 수 있다. update from post set deleted=1 where id=1\n soft delete 방식을 도입하면 테이블 조회 방식도 바뀌게 된다. select * from post where deleted=0\n 2. Soft Delete 구현 post entity @Entity\n@Getter\n@NoArgsConstructor(access = AccessLevel.PROTECTED)\n@AllArgsConstructor(access = AccessLevel.PROTECTED)\n@Builder\npublic class Post {\n\n @Id @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @NotNull\n private String title;\n\n @NotNull\n private String content;\n\n @NotNull\n private String writer;\n\n private boolean deleted = Boolean.FALSE;\n}\n\n 위 코드를 보면 post 엔티티에 default 값을 false 로 둔 deleted 변수를 추가하여 soft delete를 구현한 것을 확인할 수 있다. 이런 방식으로 구현하면 삭제할 때마다 update 쿼리를 날려야 하고 조회 할때마다 where 절을 통해 deleted=false 인 데이터만 조회하도록 쿼리를 작성해야 한다. 다음과 같은 JPA repsitory 의 delete command를 오버라이드하여 해당 작업을 간편화 할 수 있다. @Entity\n@Getter\n@NoArgsConstructor(access = AccessLevel.PROTECTED)\n@AllArgsConstructor(access = AccessLevel.PROTECTED)\n@Builder\n@SQLDelete(sql = \"UPDATE post SET deleted = true WHERE id=?\") - (1)\n@Where(clause = \"deleted=false\") - (2)\npublic class Post {\n\n @Id @GeneratedValue(strategy = GenerationType.IDENTITY)\n private Long id;\n\n @NotNull\n private String title;\n\n @NotNull\n private String content;\n\n @NotNull\n private String writer;\n\n private boolean deleted = Boolean.FALSE;\n\n public void update(String title, String content) {\n this.title = title;\n this. content = content;\n }\n}\n\n (1) @SQLDelete annotation을 통해 delete command를 deleted=true 로 update 하는 SQL command로 바꾼다. (2) @Where annotation을 통해 deleted=false 인 데이터만 조회하도록 한다. Repository public interface PostRepository extends JpaRepository<Post, Long> {\n}\n PostRepository 에는 특별한 변경점이 없다. Service @RequiredArgsConstructor\n@Service\npublic class PostService {\n\n private final PostRepository postRepository;\n\n public Long create(PostRequest postRequest) {\n Post post = postRequest.toEntity();\n return postRepository.save(post).getId();\n }\n\n public PostResponse getPost(long postId) {\n Post findPost = findPostById(postId);\n return PostResponse.builder()\n .post(findPost)\n .build();\n }\n\n public PostsResponse getPosts() {\n List<Post> posts = postRepository.findAll();\n return PostsResponse.builder()\n .postResponses(posts.stream()\n .map(post -> PostResponse.builder()\n .post(post)\n .build())\n .collect(Collectors.toList()))\n .build();\n }\n\n public Long update(Long postId,PostUpdateRequest postUpdateRequest) {\n Post findPost = findPostById(postId);\n findPost.update(postUpdateRequest.getTitle(), postUpdateRequest.getContent());\n return postRepository.save(findPost).getId();\n }\n\n public void delete(long postId) {\n postRepository.deleteById(postId);\n }\n\n private Post findPostById(long postId) {\n return postRepository.findById(postId).orElseThrow(() -> new NotFoundException(ErrorCode.ENTITY_NOT_FOUND.getMessage()));\n }\n}\n PostService 에도 특별한 변경사항 없이 원래 쓰던 deleteById 를 사용하면 update 쿼리로 변환되어 soft delete가 수행된다. 조회 메소드 또한 조회시 where 절에 deleted=false 가 추가되어 쿼리를 날리게 된다. 출처 How to Implement a Soft Delete with Spring JPA
3개의 댓글
0개의 질문
Java String Pool Java에서 문자열을 표현하는 String은 불변객체다. String name = \"jeongyun\";\nname += \"eo\";\nSystem.out.println(name); // jeongyuneo 위 코드에서 name에 문자열을 더한다고 해서 문자열의 값이 바뀌는 것이 아니라, 새로운 객체를 만들어 그 참조값을 참조하게 된다. 만약 같은 값을 갖는 문자열을 여러 번 선언한다면, Heap 영역에 매번 새로운 객체를 생성하게 될 것이다. 이는 메모리 낭비로 이어진다. 따라서 Java는 문자열 객체를 캐싱(caching)한다. 💡 캐싱(caching) 데이터를 미리 복사해 임시 저장해놓는 것 데이터 접근 시간을 줄일 수 있음 String Pool Java의 Heap 영역에는 String Pool이 존재하고, String Pool이 String 객체들을 관리한다. String Pool은 HashTable 구조를 갖고 있다. 문자열 리터럴을 사용해 문자열 객체를 생성하면 String Pool에 같은 값을 가지는 String 객체가 있는지 검사하고 있다면 그 객체의 참조값을, 없다면 새로운 String 객체를 생성해 그 객체의 참조값을 반환한다. 이러한 과정을 ‘intern’이라고 한다. String 객체를 위 코드처럼 리터럴로 생성 시 내부적으로 intern() 이라는 메소드를 실행해 수행한다. 따라서 같은 문자열은 myPet과 hisPet 두 객체의 참조값을 비교하는 동일성 비교(==)에도 true 가 반환됨을 확인할 수 있다. 반대로 new String(”문자열”) 을 이용해 생성된 객체들은 String Pool이 아닌 Heap 영역에 생성된다. 각각의 객체들은 서로 다른 참조값을 갖고 있기 때문에 이런 방식으로 생성된 myPet과 hisPet 두 객체의 참조값을 비교하는 동일성 비교(==)에서 false 가 반환됨을 확인할 수 있다. Java 6까지 String Pool은 Heap 영역 안에서도 Perm 영역에 있었다. 이때문에 String Pool에 문자열 객체가 많이 생성되거나 다른 이유로 이 영역이 가득 차게되면, 런타임 환경에서 메모리를 동적으로 늘리지 못해 OutOfMemoryException 발생했다. Java 7에서는 다른 일반 객체들과 마찬가지로 Perm 영역이 아닌 Heap 영역에 String Pool을 생성해서 OutOfMemoryException이 발생했을 때의 위험성을 줄였다. Java 8부터는 고정 크기로 많은 문제를 일으켰던 Perm 영역은 Metaspace로 이름을 변경하고 동적크기 메모리 구성으로 변경되었다.
1개의 댓글
1개의 질문
웹의 변천사 웹 1.0 : 1990~2004, static, 읽기만 가능, 구글, 네이버 웹 2.0 : 2004~현재, 상호작용, 읽기 쓰기 가능, 페이스북, 인스타그램 웹 3.0 : 미래, 지능형 웹(시멘틱 웹 기술을 이용해 웹 페이지에 담긴 내용을 이해하고 개개인에 맞춘 정보를 제공하는 것) 프론트엔드 등장배경 이미지 태그 등장 (1993) CSS 등장 (1996) 자바스크립트의 등장 (1995) - 웹 2.0 시작(2004~) AJAX의 등장 (2006) - 비동기로 화면을 동적으로 구성할 수 있게 해주는 프로그래밍 기법 플래시의 몰락 (2010) - 취약한 보안, 접근성 문제, 색인 생성 어려움 등과 같은 문제로 몰락의 길에 들어섰다 웹 대용량화, 프론트엔드와 백엔드 분리 - 웹이 급속도로 발전 해 웹페이지를 효율적으로 제작하기 위해 프론트, 백으로 분리 출처 : [도서] 아는만큼 보이는 프런트엔드 개발
0개의 댓글
0개의 질문
웹 애플리케이션 웹 브라우저에서 동작하며 사용자와 상호작용 이 가능한 소프트웨어, 줄여서 웹앱 웹 개발 웹 애플리케이션을 만드는 일 사용자와 상호작용을 어떻게할까? 클라이언트(웹 브라우저)의 요청 서버의 응답 클라이언트-서버 구조 웹개발 구조 프론트엔드 개발 - 사용자가 웹 애플리케이션을 사용할 수 있도록 눈에 보이는 화면과 기능 개발 백엔드 개발 - 서버에서 동작하는 부분 개발, 웹 애플리케이션에서 다루는 데이터 관리,처리 출처 : [도서] 아는만큼 보이는 프런트엔드 개발
0개의 댓글
0개의 질문
로그인을 직접 구현하면서 발생한 문제점을 정리해보겠다. 먼저, JWT 를 사용해 로그인을 구현하기로함 이유: 세션은 스케일아웃이 어려움, 쿠키에 user table의 pk 값만 담아도 충분함 엑세스 토큰, 리프레시 토큰을 어디에 두어야 하는가 검색해보니 블로그마다 구현한 방식이 다름 액세스 토큰은 일반 쿠키에 담자 - 보안에 좋지 않다. 그러므로, 유효시간을 짧게 둔다. 리프레시 토큰은 http only, secure, samsite=lax 쿠키에 담자 - 쿠키 중 가장 안전한 방식 Q. 그런데, 액세스 토큰 자체를 리프레시 토큰처럼 안전한 쿠키에 보관하면 되는것 아닌가? A. 그래도 보안에는 차이가 없지만, 액세스 토큰을 일반 쿠키로 두었을 때, next.js 와 같이 클라이언트와 백엔드 사이에서 쿠키를 사용할 일이 생기면 http only 쿠키는 중간에서 사용할 수 없다 . (수정) 도메인이 같다면 백엔드, next 서버 모두 쿠키를 사용할 수 있다. 따라서 액세스 토큰도 안전한 쿠키에 저장해도 된다. 그럼 리프레시 토큰은 절대 안털림? 절대 안털린다고는 당연히 말할 수 없다. 완벽한 보안이 존재하면 아무도 고민 안할듯 그래서 리프레시 토큰도 털릴 경우를 대비하면 좋다. RTR RTR 방식을 사용해서 리프레시 토큰이 털리는 것을 어느정도 방지해줄 수 있다. RTR은 처음 로그인 시 엑세스, 리프레시 토큰을 발급받고, 이후 액세스 토큰이 만료되면 리프레시 토큰을 사용해 새로운 리프레시, 액세스 토큰을 발급받는 방식이다. 이전에 발급된 리프레시 토큰은 쓸모가 없어진다. 자연스럽게 유저가 계속 서비스를 사용하면, 로그인이 영원히 유지된다. 시나리오 액세스토큰만 털어간다 30분 정도는 유저인척 할 수 있다. 이후 액세스 토큰 만료 시, 리프레시 토큰이 없기에 더이상 유저인척 할 수 없다. 액세스토큰, 리프레시 토큰 둘다 털어간다. 마찬가지로 30분 정도 유저인척한다. 이후 액세스 토큰 만료되면, 해커가 먼저 새로 발급받는다. -> 유저가 이후에 다시 로그인해, 새로운 리프레시, 액세스 토큰을 발급받고, 해커의 리프레시 토큰을 무효화 시킨다. 유저가 먼저 새로 발급받는다. -> 해커의 리프레시 토큰이 무효화된다. 물론, 리프레시, 액세스 토큰이 털렸는데 유저가 로그인을 하지 않는다면 해커는 영원히 유저인 척 할 수 있다.
0개의 댓글
0개의 질문