본문 바로가기
Javascript/YDKJS

YDKJS (유돈노JS) 부록A - 암시적스코프

by ginny. 2024. 10. 6.

암시적스코프

1. 매개변수스코프

 

함수매개변수는 함수스코프에서 지역으로선언한변수와 동일함.(단순매개변수일경우)

작가왈 예외 - 기본값이 있는 매개변수, ...나머지매개변수, 비구조화매개변수(디스트럭쳐링.구조분해할당)

  • 매개변수목록(args)이 자체 스코프를 형성하고, 함수스코프는 매개변수목록(args)스코프에 중첩됨

주의) 지역변수로 매개변수를 섀도잉하지 말자, 기본매개변수에서 다른매개변수를 참조하지 말자

동작 과정 (매개변수에 함수 표현식이 있을 경우의 스코프 형성)

function example(x, y = () => x) {
    console.log(x);  // 첫 번째 매개변수 x 출력
    console.log(y());  // y 함수 호출하여 반환값 출력
    var x = 10;
    console.log(x);  // var로 재선언한 x 출력
}

example(5);

함수 호출 시 (example(5))

함수를 호출하면서 첫 번째 매개변수 x는 5로 전달됩니다. 두 번째 매개변수 y는 전달되지 않았으므로 기본값으로 설정된 () => x가 사용됩니다. 이 함수는 스코프 내의 x를 참조하게 됩니다.

첫 번째 console.log(x)

x는 매개변수로 전달된 값 5를 출력합니다. 

두 번째 console.log(y())

이 함수는 호출 시 현재 스코프 내에서 매개변수로 전달된 x의 값을 참조합니다. 현재 x는 5이므로 y()는 5를 반환합니다.

var x = 10; 실행

그다음 줄에서 x는 10이 할당됩니다. 

 

첫 번째 console.log(x)에서 5가 출력되는 이유는?

매개변수로 전달된 x가 지역 변수 x가 덮어씌워지기 전까지 우선적으로 사용되기 때문입니다.

var 선언이 호이스팅되지만, 매개변수가 존재할 경우, 그 값으로 먼저 초기화됩니다. 

과거 코드와의 호환문제로 이렇게 함수에 매개변수와 같은이름의 지역변수가 있는경우 x를 undefined로 초기화하지않고 ,매개변수 x를 매개변수값으로 초기화한다. x는 함수 스코프에서 동일한 이름을 가지므로, 지역 변수 x는 매개변수의 값 5로 먼저 초기화됩니다. ??

 

내생각>> 엥아니지, var id로 선언한것은 이미 매개변수id가 선언되어있으니 다시 선언한거는 무시되잖아.

그러니까 별도스코프를 가지는건아닌거지않나? 그리고 매개변수스코프가 따로 있다면 아래 코드에서 에러가 나면안됨

let x = 1;
function example(a = x) {
  let a = 2;
  console.log(a);  
}
example();

그러나 위 코드에서 let a부분에서 에러가남(이미 a는 선언되어있다고.) 즉, 매개변수a는 이미 함수스코프내부에 선언및 할당이 되어있는 상태임!


이 예시에서 함수 내부의 x가 아닌 함수 밖의 x가 기본값으로 사용되었어요. 이는 기본값이 평가되는 시점이 함수 본문 내부 코드 실행 이전이기 때문에 발생합니다.

 

gpt왈:

기본값이 있는 매개변수, 나머지 매개변수, 비구조화 할당을 사용하는 매개변수의 경우에도 모두 함수의 지역 스코프에 속합니다. 기본값이 있는 매개변수도 여전히 함수의 스코프 안에 존재하며, 그 자체로 별도의 스코프를 가지는 것은 아닙니다. 따라서 "자체 스코프를 가진다"라는 표현은 다소 부정확하며, 모든 매개변수는 함수의 스코프 안에서 동작하지만, 기본값을 평가하는 시점에 차이가 있을 수 있습니다.

기본값이 있는 매개변수의 스코프: 기본값은 함수가 호출될 때 평가되며, 기본값을 평가하는 과정은 매개변수 자체 스코프에서 일어납니다. 이 스코프는 함수 스코프보다 앞서서 적용되는데, 이로 인해 기본값 평가 시 다른 매개변수의 값을 참조하거나 함수 스코프의 변수를 사용할 수 없습니다. 기본값을 평가하는 매개변수의 스코프는 그 자체로 하나의 "별도 스코프"로 간주될 수 있습니다.

기본적인 매개변수 스코프 개념:

매개변수는 기본적으로 함수의 스코프 내부에 포함됩니다. 다시 말해, 매개변수는 함수 본문의 지역 변수처럼 취급됩니다. 그래서 매개변수 자체가 함수 스코프 외에 "따로" 스코프를 가지는 것은 아닙니다. 대부분의 경우, 매개변수는 함수가 실행되는 동안 그 함수의 스코프 안에 존재하는 지역 변수입니다.

기본값 매개변수의 경우 (약간의 차이점):

기본값을 가진 매개변수는 좀 더 특별한 경우가 있습니다. 기본값 매개변수는 함수가 호출될 때 기본값을 평가하는 단계에서 다르게 동작할 수 있습니다.

기본값 평가 과정에서 함수 내부 스코프와 약간 다른 방식으로 동작할 수 있기 때문에, 일부 자료에서는 이를 "별도의 스코프"로 설명하기도 합니다. 이때 "별도의 스코프"라는 것은 정확히 말하면 기본값이 평가되는 시점에서 다른 매개변수나 함수 내부의 변수를 참조하지 않는 것을 의미합니다. 실제로 기본값 매개변수는 함수 본문의 스코프보다 우선적으로 평가되기 때문에, 함수 내부에서 나중에 정의된 변수에 접근하지 않습니다.

 

매개변수와 실행 컨텍스트

스코프는 컴파일 시에 정의되지만, 함수 호출 시 실행 컨텍스트 내에서 매개변수의 값이 설정되고 초기화되는 과정이 있기 때문에, 매개변수는 함수가 호출될 때마다 새로운 값을 가지게 됩니다.

 

 

2. 함수명스코프

함수자체의 스코프에 함수표현식이름이 추가된다?

함수표현식의 이름식별자는 자체암시적스코프를 가진다.

함수 이름 식별자는 함수 내부에 자체 스코프를 가집니다. 즉, 함수 이름은 함수 본문 내부에서만 참조 가능하며, 함수 외부에서는 접근할 수 없습니다.

주의) 함수표현식이름과 동일한 변수를 함수본문에서 let으로 선언하지말자

 

익명함수, 기명함수

이름추론은 불완전하다

렉시컬이름을 사용하면 자기참조가 가능하다

이름은 설명을 제공하기때문에 유용하다 > debugging시 유용하다!

화살표함수에는 렉시컬이름이 없다.

즉시실행함수에도 이름이 필요하다

 

스택트레이스: 프로그램 실행과정에서 호출된 메서드의 순서와 위치정보 나타내는것

 

 

추론된이름 inferred name

언제 이름추론이 일어나는가?

>> 익명함수표현식 (그러나 함수표현식을 단순할당 아닌 다른형태로 하는경우 대다수의 이름추론안됨)

**var stillNotNamed = function butThisIs(){ } >>기명함수표현식. 이때는 이름추론됨! 

 

기명함수표현식 경우 함수에 이름이 붙어 있지만, 그 이름은 함수 내부에서만 유효함. 외부에서는  함수할당된 변수 이름으로 접근해야 합니다. (함수내부에서만 butThisIs를 참조가능, 함수외부에서 이 이름으로 함수에 접근할 수 없다.)

 

1. 이름추론이 되는경우 : 함수표현식을 단순할당했을 경우

var notNamed = function() {...} notNamed.name //notNamed

var config = { cb:function(){..} } config.cb.name //cb

 

2. 이름추론이 안되는경우? 단순할당 이외의 경우

1. 즉시실행함수 : (function() { console.log("익명 함수"); })();

2. 콜백으로 전달된 익명 함수: setTimeout(function() {}, 1000);

**콜백으로 전달된 익명 함수 - 이름추론이 안되는경우

function a(url, cb) { 
console.log(cb.name); //결과 : ""빈문자열
}  

a("someurl", function(){});

**콜백인자로 전달된 익명함수 - 이름추론이 되는경우

function a(url, cb=function(){}) { 
console.log(cb.name); //결과 : cb
}  

a("someurl");

3. 메소드 동적할당

var obj={}

obj.F = function(){}

F.name; //""빈문자열

 

4. 디스트럭쳐링

var [noName] = [ function(){} ];

noName.name //""빈문자열

 

화살표함수의 this는 자체this가지지않는다. 렉시컬스코프에 의해 결정된다.

화살표함수안에 this는 다른변수참조처럼 작동. 다른 렉시컬변수처럼 취급함.

this를 렉시컬변수처럼 사용해야하는 경우?

var self=this

내부함수표현식.bind(this)

드물게 렉시컬this가 필요한경우에만 화살표함수를 사용하자.

 

즉시실행함수도 이름이 있어야한다.

(function(){..})() 이렇게해야 파서가 function키워드를 만났을때 함수선언문으로 해석하지않는다.

다른방식으로 정의도 가능함. function키워드앞에 !,+,*(단항연산자)를 놓아 표현식 만들수있음

void도 가능.

 

호이스팅의 장점

실행가능한 코드먼저, 함수선언은 아래쪽에 배치 >> 실제실행되는 코드를 먼저 보기때문에 읽는순서가 위에서아래로,가독성굿. (변수호이스팅은 아님)

변수선언의 의미있는 역순배치 >>대부분은 가독성 좋지않다. 예외경우, 비공개구현의도..사용용을 먼저하겠다. 선언은 아래에서 하고..

 

var에 대한 변론

var에 문제가 있는건 절대아니다.

let은 여러분의 친구입니다.

const의 유용성은 제한적이다. >> 값 불변성과 할당불변성은 다름! const는 할당불변성. (여기서 혼동이..)let,var써도 재할당만 하지않으면(컴파일러가 보장하진않지만)실질적으로 상수처럼 작동한다.

var,let 사용하는 최선의 방법은 둘의 장점을 모두 취하는것이다.

언제 var? 함수의 최상위스코프에서. 왜냐면 함수스코프를 다루는데 가장 적합한도구가 var이기때문

모든곳에 let을 사용하면 어떤게 지역변수고 어떤게 함수전체변수인지 구분힘들다. 블록안에서는 let

 

TDZ는 const에서 비롯되었다.

let,const는 왜 var처럼 undefined로 자동초기화되지않을까?

만약 const도 undefined자동초기화된다면,,

{ console.log(name); //여기서는 undefined

...수많은 코드....

const name="John" //여기서는 John이라는 값을 가진다. 상수는 하나의값이라는 상식에 위배된다..

}

그럼 let은?

작가왈 : let은 var에 더 가깝다. 

 

 

 

'Javascript > YDKJS' 카테고리의 다른 글

1008 유돈노  (0) 2024.10.08
유돈노  (0) 2024.10.08
1002 유돈노스터디  (0) 2024.10.02
YDKJS (유돈노JS) Ch3 - 스코프체인  (0) 2024.10.02
YDKJS (유돈노JS) Ch1&2 - 스코프와 렉시컬스코프  (0) 2024.09.25

댓글