
Scope : 1. (무엇을 하거나 이룰 수 있는) 기회
2. (주제, 조직, 활동 등이 다루는) 범위
[네이버 어학사전]
지금 현재 말하는 Scope의 의미는 범위에 가깝다고 말할 수 있다.
다시말해, 변수의 Scope는 변수를 사용할 수 있는 범위로 해석이 가능하다.
ES5 까지는 Scope의 범위가 함수 단위의 Scope이다.
아래 코드를 보며 이해해 보자.
// 전역 변수 Scope
var num1 = 5
var num2 = 10
if (num1 < num2) {
var num3 = 30
} else {
// 전역 변수는 공유되기때문에 여기서는 var를 생략가능
var num3 = 50
}
var func = function() {
// 함수 단위의 Scope가 시작
var num1 = 15
var num4 = 20
console.log(num1)
// 15, 현재 스코프에 num1이 있기때문에 현재 스코프의 값을 출력한다.
}
console.log(num3)
// 30, 함수단위 스코프이기 때문에 같은 전역 공간에 있는 num3값을 출력한다.
func()
console.log(num4)
// Uncaught ReferenceError : num4 is not defined,
// 함수 단위의 스코프이기 때문에 함수에서 쓰인 변수는 함수에서만 사용 가능하다.
여기서 자바와의 큰 차이점 중 하나를 볼 수 있다.
다른 언어들은 블록 단위의 스코프를 가지고 있어, if문에서도 별도의 스코프를 가지고있지만
자바스크립트에는 함수 단위의 스코프가 존재 한다.
chaining : 1. 체이닝
2. 연쇄(적 처리)
[네이버 어학사전]
var num1 = 10
var func1 = function() {
// 외부 함수 Scope(func1)의 시작
var num2 = 15
var func2 = function() {
// 내부 함수 Scope(func2)의 시작
// 1. 현재 스코프(func2)에는 num1 변수가 존재 하지 않는다.
// 2. 스코프 체인을 타고 스코프 func1로 올라간다.
// 3. 스코프 func1에도 num1 변수가 존재 하지 않는다.
// 4. 스코프 체인을 타고 전역 스코프로 올라간다.
// 5. 전역 스코프의 num1변수를 참조해 num1을 출력한다.
console.log(num1) // 10
// 1. 현재 스코프(func2)에는 num2 변수가 존재 하지 않는다.
// 2. 스코프 체인을 타고 스코프 func1로 올라간다.
// 3. 스코프 func1에 num2 변수를 참조해 num2를 출력한다.
console.log(num2) // 15
}
func2() // 내부 함수 func2 호출
}
func1() // 함수 func1을 호출
'use strict'
// 전역 스코프 상단에 위 구문을 넣어주거나
// 사용하려는 함수 바디 상단에만 넣어주면 된다.
// 미지원 브라우저는 그냥 문자열로 인식하고 오류를 발생시키지 않는다.
var num1 = 10
var func1 = function() {
// 전역 스코프에 존재하는 변수이기때문에 덮어씌우면서 정상 작동한다.
num1 = 30
// 스코프 체인 상에 존재하지 않는 변수를 var없이 선언하면 오류 발생.
num2 = 50 // Uncaught ReferenceError: num2 is not defined
}
// 스코프 체인 상에 존재하지 않는 변수를 var없이 선언하면 오류 발생.
num3 = 100 // Uncaught ReferenceError: num3 is not defined
func1()
scope는 함수를 호출할 때가 아니라, 선언할 때 생긴다.console.log 가 어떻게 찍힐지 생각해 보자.var result = 'AAA'
function func() {
console.log(result)
}
function func2() {
result = 'BBB'
func()
}
func2() // BBB
var result = 'AAA'
function func3() {
console.log(result)
}
function func4() {
var result = 'BBB'
func3()
}
func4() // AAA
func3의 result는 func4의 지역변수 result가 아니라, 전역변수 result를 바라보고 있다. 이것을 lexical scoping이라고 한다.scope로부터 가장 가까운 곳에 있는 변수를 참조 한다.func3 함수 안의 result 변수는 선언시 가장 가까운 전역변수 result를 참조 한다.func3 함수가 한 번 선언된 이상 전역변수를 바라보는 result 변수가 다른걸 바라보게 할 수 없다.지양 해야 한다. 이유는, 변수가 섞일 수 있기 때문이다. 다른사람과 협업해 개발하고, 라이브러리 등을 사용하다보면, 같은 변수이름을 사용해 겹치게되는 일을 겪을 수 있다. 해결 할 수 있는 방법 중 하나는, 전역변수 대신 함수 안에 넣어 지역변수로 넣어 사용하거나, 객체 안의 속성으로 만들어 사용하는 것이다.var obj = {
result: 'AAA',
func: function() {
console.log(this.result)
}
}
obj.result,obj.func() 와 같이 접근 해야 하기때문에 obj를 통째로 바꾸지 않는 이상 겹치게 되는 염려를 덜 수 있다. 하지만, 위 방법의 단점은 누군가 고의적으로 result와 func를 바꿀 수 있다. obj를 통째로 바꾸지 않더라도, 코드 밑에 obj.result = "BBB"를 추가 한다면 obj.func()를 할 경우 AAA대신 BBB가 출력 될 것이다. 그걸 방지 하기 위해서는 아래와 같이 하면 된다.var f = function() {
var result = 'AAA'
function func1() {
console.log(result)
}
return { func: func1 }
}
var newFunc = f()
newFunc.func() // AAA
f() 하게 되면, return에 의해 {func: function(){console.log(result)}}가 newFunc에 저장이 된다. 후에는 newFunc를 통해 func에 접근 할 수 있다. 하지만, result에는 접근 할 수 없다. 함수로 감싼 후 return을 통해 공개변수(func)만 공개하고, 비공개변수(result)는 비공개 하는 방법으로 진행 할 수 있다. 위 코드를 조금 변경하면, 아래와 같다.var newFunc = (function() {
var result = 'AAA'
return {
func: function() {
console.log(result)
}
}
})()
newFunc.func() // AAA
f같은 변수를 한번 더 거치는대신, newFunc에 바로 집어넣어서 사용 할 수 있다. 위의 방법은 IIFE(즉시 호출 함수 표현식) 또는 모듈 패턴이라고 한다.비공개 변수가 없는 자바스크립트에 비공개 변수 기능을 만들어 주는 역할을 한다.아래 코드를 바로 실행 하지말고, 실행결과를 예상 해 보고, 실행해 예상한 결과와 일치 하는지 비교 해보자.
var result = 'hello'
function func(s) {
console.log(s + ' ' + result)
}
function func1() {
var result = 'Bye'
console.log(result)
func('Hi,')
}
func1()