스코프란 범위의 의미를 가진다.
"변수의 유효범위" 로 사용된다.
각종 선언 키워드 let, const의 범위가 어떻게되는집 보자.
let greeting = "hello";
function greetSomeone() {
let firstName = "Josh";
return greeting + " " + firstName;
}
greetSomeone(); // => Hello Josh
firstName; // ReferenceError
함수 내부는 Local Scope로 지역적인 스코프를 가진다. ( 지역변수 , 로컬변수 이런말 쓰던거 기억해보자.)
전체의 스코프를 가지는것은 전역변수 글로벌변수 라는말을 쓴다. Global Scope를 가진다.
즉 함수내부에서 선언된 변수는 밖에서는 모른다. 그러므로 사용할수없다.
다른언어와 동일할지 모르겠지만 함수가 종료되면서 메모리에 저장되어있던 값을 풀어준다.
즉 더이상 할당되지않은 메모리 주소가 되는것이다. ( 아마 비슷하게 동작하지않을까? )
JavaScript는 기본적으로, 함수가 선언되는(lexical) 동시에 자신만의 Scope를 가집니다.
안쪽 Scope에서 바깥 변수/함수를 접근하는 것은 가능
빠깥쪽 Scope에서 안쪽 변수/함수를 접근하는것은 불가능
스코프는 중첩이 가능하다.
- 함수안에 함수 넣을 수 있다.
global scope는 최상단 Scope로 전역변수는 어디서든 접근이 가능하다.
지역변수는 함수 내에서 전역변수보다 더 높은 우선순위를 가진다.
let name = "Richard";
function showName(){
let name = "Jack"; // 지역변수
// ShowName 함수 안에서만 접근 가능
console.log(name); //
}
console.log(name); // Richard
showName();// Jack
console.log(name); // Richard
서로다른 취급을 받는 name 변수
let name = "Richard"
function showName(){
name = "Jack"
// 선언( let ) 이 없기 때문에 , 바깥 scope에 있는 name이라는 변수를 가져옵니다.
console.log(name);
}
console.log(name); // Richard
showName();// Jack
console.log(name); // Jack
Block ?
중괄호로 시작하고 , 끝나는 단위
if(true) {
cosole.log("i am in th block");
}
for( ; ; ) {
console.log(i);
}
{
console.log("katsukichi");
}
for(let i=0; i<5; i++) {
console.log(i); // 다섯번 iteration
}
console.log('final i:', i); // reference Error
for문이 종료되면 for내부에 초기화식으로 선언된 i는 메모리할당이 해제된다.
그러므로 i는 선언되어있지 않다고 뜰것이다.
Error
for(var i=0; i<5; i++) {
console.log(i); // 다섯번 iteration
}
console.log('final i:', i); // 5
값이 변하지 않는 변수, 즉 상수를 정의할때 사용하는 키워드
let 키워드와 동일하게 Block Scope를 따른다.
값을 재정의 하려ㅑ고 하면 TypeError를 낸다.
재선언을 막아주는 친구 : let,const 애용하자. ( 실수로인한 버그를 막아준다 )
전역 범위를 대표하는 객체 window
global Scope에서 선언된 함수, 그리고 var키워드를 이용해 선언된 변수는 window 객체와 연결
전역범위에 너무 많은 변수를 선언하지말자 ( 임베디드는 예외인듯.. )
window 객체 내부를보면 전역범위에서 쓸수있는것들이 쫙 나열되어있다.
var키워드로 선언된 변수,함수 는 window.foo() 처럼 window전역 객체를통해서 볼수도 있다.
function showAge() {
//age 는 전역 변수로 취급됩니다.
age = 90;
console.log(age);
}
showAge(); // 90
console.log(age); //90
// age === window.age
이렇게 되는것. 조심해서 선언 키워드없이 변수를 초기화지 말자!
이런것을 방지하려면 ?
Strict Mode를 사용하세요.
'use strict';
를 최상단에 선언시 사용가능하다.
자바스크립트에서는 다른 컴퓨터 언어와는 조금 다른 특성을 종종 가지고 있습니다. 그 중 종종 사용되는 클로져 라는 개념에 대해서 알아보겠다.
함수와 함수가 선언된 어휘적(lexical)환경의 조합
클로져 어려워하지말자! -> 스코프의 연장이구나.
function outerFn(){
let outerVar = "outer";
console.log(outerVar);
function innerFn() {
let innerVar = "inner";
console.log(innerVar);
}
}
let globalVar = "global";
outerFn();
다음중 innerFn함수에서 접근할수있는 Scope는 총 몇개 인가요 ?
아마도 확신할수있는것은 innerFn인 자기 자체블럭과 outerFn의 function block 까지는 확정적으로 접근가능한데
globarVar 를 잘생각해보자. 음 먼저 선언되었다 늦게선언되었다 차이인데.
이것을 hoisting개념이라고해야하나 아직 배우지않는 내용을 섞어서 받아들여야할지 고민이된다.
기본적으로 global도 접근가능하다고 알자. ( 순차적으로 알려주겠지.. )
이때 코드를좀 바꿔보겠다.
function outerFn(){
let outerVar = "outer";
console.log(outerVar);
function innerFn() {
let innerVar = "inner";
console.log(innerVar);
}
return innerFn; // 함수자체를 리턴해준다면 ?
}
outerFn(); // 과연 ?
함수가 실행된것은 아니지만, 함수 자체를 리턴한다.
좀더 문제를 꼬아보겠다 .
function outerFn(){
let outerVar = "outer";
console.log(outerVar);
function innerFn() {
let innerVar = "inner";
console.log(innerVar);
}
return innerFn; // 함수자체를 리턴해준다면 ?
}
outerFn()(); // 1. "outer"한번 찍히고 function innerFn()함수자체가 자리에남고 그자리에서 다시 함수실행문이 사용되어서 innerFn이 실행된다. 그래서 inner가 찍힌다?
let innerFn = outerFn(); // 2. "outer"찍히고 innerFn에는 이제 전역변수에 함수가 들어가게되고
innerFn(); // 3. innerFn()는 모르지않을까? referenceError가 뜨나 ?
각각 무엇이 찍힐까?정답은 ?
그래서
클로저가 뭔데?
: 외부 함수의 변수에 접근할 수 있는 내부 함수 또는 , 이러한 작동 원리를 일컫는 용어!!!
위에 예제에서는 function innerFn()자체가 클로저 함수 라고할수있다.
이러한 패턴 자체를 클로저 패턴이라고 한다.
이런패턴이 자주쓰이고 유용하기때문에 이름붙여준거다.~!!!
커링 ? : 함수 하나가 n개의 인자를 받는 대신, n개의 함수를 만들어 각각 인자를 받게 하는 방법
function adder(x) {
return function(y) {
return x + y;
}
}
adder(2)(3) ; // 5
let add100 - adder(100); // x의 값을 고정해놓고 재사용 할 수 있다.
add100(2); //102
add100(10); // 110
let add5 = adder(5);
add5(2) ; // 7
html태그를 만들어주는
function htmlMaker(tag){
let startTag = '<' + tag + '>';
let endTag = '</' + tag + '>';
return function(content){
return startTag + content + endTag;
}
}
let divMaker = htmlMaker('div');
클로저 모듈 패턴 : 변수를 스코프 안쪽에 가두어 함수 밖으로 노출 시키지 않는 방법
function makeCounter() {
let privateCounter = 0;
return {
increment : function(){
privateCounter++;
},
decrement : function(){
privateCounter--;
},
getValue : function(){
return privateCounter;
}
}
}
문제!!
let counter1 = makeCounter();
counter1.increment();
counter1.increment();
counter1.getValue(); // 2 ? 정답 : 2
let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue(); // 1 ?
객체를 리턴으로 돌려주느데 그 객체 내부에 매서드 3개 ? 존재하고있고
let counter1 = makeCounter() 하면 counter1은 객체가 된거처럼 매소드 이용이 가능하다.
privateCounter가 증가한다.
privateCounter는 스코프에 의해서 밖에서 직접 거드릴수없다.
increment , decrement 등의함수들로 간접적으로 바꿔줄수있다.
그럼 왜 밖에서 수정하게 못하게 만들어야하는가 ?
let type = "현금"; // 반드시 현금 또는 카드 여야함
내가 직접 건드리지않고 내부에서 제어하면 안전하다고 생각할수있다.
Java나 c++하면 private 한 변수를 기억해보자. 실제로 그런 안정성때문에 사용했던거 같다.
counter1 , counter2 각각 다르게 독립적으로 privateCounter를 가지고있기때문에
재사용이 가능해진다
핵심
클로저란 : 결국 외부함수에 접근할수있는 내부함수 또는 이러한 작동 원리