스코프는 참조 대상 식별자를 찾아내는 규칙이라고 한다. 자바스크립트는 이 규칙대로 식별자를 찾는다고 한다. 전역 혹은 코드 블록, 함수 내에 선언하여 변수는 중첩될 수 있고, 자신이 어느곳에서 선언 되었는지에 따라 코드가 자신을 참조하는 범위를 갖는다고 한다.
개인적으로 알고리즘 풀 때 이 스코프 개념을 알게 되면 비교적 수월하다고 생각한다.
스코프의 구분은 2가지로 나눠진다고 한다.
코드의 어느곳에서든지 참조할 수 있는 범위라고 한다. 선언하면 참조가능하다는 기본적인 기능을 따른다고 생각한다.
let a = 1
const test=()=>{
console.log(a)
}
test() // 1
console.log(a)// 1
코드블록, 함수내에서의 범위를 갖으며 자기 자신과 하위 범위에서만 참조할 수 있다고 한다.
let a = 'a'
const test=()=>{
let a = 'b'
console.log(a)
}
test() // 'b'
console.log(a) //'a'
//함수 내 선언된 a 는 지역스코프를 따른다.
반대로 함수내에 선언된 변수는 함수 밖에서는 유효하지 않는다고 한다.
let a = 'a'
const test=()=>{
let b = 'b'
}
console.log(a) // 'a'
console.log(b) //'ReferenceError: b is not defined'
//함수 내 선언된 a 는 지역스코프를 따른다.
렉시컬 스코프는 어디서 호출하는지가 아니라 어디서 선언하였는지에 따라 결정되는 것을 의미 한다고 한다. 다른 말로는 Static Scope라고 한다.
(220621) 어디서 호출 하는지에 따른 스코프는 동적 스코프라고 하며,이전에는 Javascript가 동적 스코프였다고 한다. ES5 부터 정적 스코프가 도입되었다고한다.
정적 스코프는 자신이 속한 영역부터 참조하며, 없을 경우 상위 스코프로 넘어가는 것이 특징이다. 이런 동작을 이해하려면 실행 컨텍스트(Execution Context)를 아는 것이 도움이 되었다.
let a = 'a'
const test01=()=>{
let a = 'b'
test02()
}
const test02=()=>{
console.log(a)
}
test01() // 'a'
test02() // 'a'
자바스크립트에서는 실행 단계에서 코드들의 스코프를 결정한다고 한다. 그렇기 때문에 test02() 는 글로벌 범위에서 선언 되었으므로 'a'를 따른다고 한다.
[220411 TIL - 재귀함수, var, let, const 차이]
https://velog.io/@eotkds/220411-TIL
hoisting 과 scope 를 작성하면서 위에 TIL 링크에 있는 근본적인 문제를 명쾌하게 설명하지 못한거 같아 찜찜했다. 관련 블로그를 찾긴했는데 이게 또 Scope의 영역인지 Hoisting의 영역인지 헷갈렸다. 결론적으로는 Scope 에 영역에 가까워 추가 포스팅 하려고 한다.(사실 let, const, var 선언같기도 하고...이리붙였다 저리 붙였다 했다.😂)
시작은 이러했다.
for(let i = 0; i < 5; i++){
}
console.log(i) // ReferenceError: i is not defined
for(var k = 0; k < 5; k++){
}
console.log(k) // 5
이런 이유는 각 선언 방식에 따라 유효 범위(Scope)가 다르기 때문이라고 한다. var
은 function scope이고, let
과 cosnt
는 block scope 이기 때문이라고 한다.
위 예시 에서처럼 {} 는 블록으로 볼 수 있다고 한다. 그렇기 때문에 let은 {}(블록) 밖에서는 참조가 불가능 하다.
(220621) if...else문이나 for문은 블럭문이라고 한다.
이와 관련해서 예시가 있다. var와 관련하여 함수 스코프에 특징이 있으니 참고 바란다.
//var 사용할 경우
const arr = []
for(var i = 0 ; i <5; i++){
arr.push(function(){
console.log(i)
})
}
arr[0]() //5
arr[1]() //5
...
arr[4]() //5
//let을 사용할 경우
const arr = []
for(let i = 0 ; i <5; i++){
arr.push(function(){
console.log(i)
})
}
arr[0]() //0
arr[1]() //1
...
arr[4]() //4
var
는 전역 변수인가그렇지는 않다고 한다. ㅠ var
은 함수스코프에서는 유효 하다고 한다. 아래 예시에서 설명하겠다.
javascript의 특징이자 단점이기도 한다고 하는데, 동적 타입의 변수라고 한다. 반대로는 정적 타입의 변수가 있다고 한다. 아래 예를 보자
x = 1
console.log(x) // 1
위 처럼 var, let, const에 선언을 하지 않은 변수에 대해 에러가 발생하지 않았다. 값을 대입하는 순간 전역변수 처리가 되었기 때문이라고 한다.
음... 위에 for문을 다시 정리하자면 var
선언이 전역변수 처리 되었기 때문에 참조가 된 것이 아니다. var
는 for문과 같은 block에서는 scope를 무시한다고 이해했다.
var
는 함수 스코프에서만 유효 하다고 한다.
좀 더 이해를 도울 수 있는 예시를 올려본다.
function x() {
a = 'a';
var b = 'b';
}
x()
console.log(a) // 'a'
console.log(b) // ReferenceError: b is not defined
위 예시는 var
로 선언한 b는 지역변수 처리 되었고, a는 전연변수 처리되어 참조가 되었다. b는 함수 스코프를 따른 셈이다.
var b = 'bb'
function x() {
a = 'a';
var b = 'b';
}
x()
console.log(a) // 'a'
console.log(b) // 'bb'
위 예시로 좀 더 이해가 잘 되었다. 함수 레벨 안에서의 b = 'b'는 지역 변수 처리 되어 코드 아래에서 b 변수는 전역 변수 처리된 값을 참조하여 'bb'를 출력 하였다.
이것과 관련하여 hoisting 개념 또한 다음 포스팅에 올리려고 한다.
(220504)아니나다를까 이해하고 있다고 생각했던 개념을 정리하는 순간 와르르 무너진 기분이다. 정리하면서 중간중간 수정해서 내용이 엉망진창이라고 생각한다. 글쓰는건 정말 어렵당.
[[JavaScript] 스코프(Scope)란?,velog, 2022년05월03일 접속]
https://velog.io/@bsjp400/JavaScript-%EC%8A%A4%EC%BD%94%ED%94%84Scope%EB%9E%80
[자바스크립트 - 렉시컬 스코프(Lexical Scope), tistory, 2022년05월03일 접속]
https://ljtaek2.tistory.com/145
[var, MDN WEB DOCS, 2022년05월03일 접속]
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/var
[[javascript]for 문에서 var대신 let사용하는 이유 + setTimeout(),tistory, 2022년05월04일 접속]
https://fromnowwon.tistory.com/entry/for%EB%AC%B8-let
[[javascript]변수, naver blog, 2022년05월04일 접속]
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=yuyyulee&logNo=221582834075
[[JavaScript] 스코프(Scope)와 변수 선언 (var, let, const 키워드 차이점),HANAMON,2022년05월04일 접속]
https://hanamon.kr/javascript-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-%EB%B3%80%EC%88%98%EC%84%A0%EC%96%B8%ED%82%A4%EC%9B%8C%EB%93%9C-%EC%B0%A8%EC%9D%B4%EC%A0%90/
[block, MDN, 2022년06월21일 접속]
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/block