어휘 범위 지정에 대한 간략한 소개는 무엇입니까?
어휘 범위 지정에 대한 간략한 소개는 무엇입니까?
답변:
예를 통해 이해합니다. :)
먼저 C와 같은 구문으로 어휘 범위 ( 정적 범위 라고도 함 ) :
void fun()
{
int x = 5;
void fun2()
{
printf("%d", x);
}
}
모든 내부 레벨은 외부 레벨에 액세스 할 수 있습니다.
C와 유사한 구문 으로 Lisp 의 첫 번째 구현에서 사용되는 동적 범위 라는 또 다른 방법이 있습니다 .
void fun()
{
printf("%d", x);
}
void dummy1()
{
int x = 5;
fun();
}
void dummy2()
{
int x = 10;
fun();
}
여기에 fun
액세스하거나 할 수 x
있는 dummy1
하거나 dummy2
, 또는 x
호출하는 것이 어떤 함수 fun
와 x
그 안에 선언은.
dummy1();
5를 인쇄합니다
dummy2();
10을 인쇄합니다.
첫 번째는 컴파일 타임에 추론 할 수 있기 때문에 정적이라고하고, 두 번째는 동적이며 함수의 체인 호출에 의존하기 때문에 동적이라고합니다.
나는 눈에 대한 정적 범위 지정이 더 쉽다는 것을 알았습니다. 대부분의 언어는 결국 이런 식으로 갔다. 심지어 Lisp도 마찬가지이다. 동적 범위 지정은 모든 변수의 참조를 호출 된 함수에 전달하는 것과 같습니다.
컴파일러가 함수의 외부 동적 범위를 추론 할 수없는 이유의 예로 마지막 예제를 고려하십시오. 다음과 같이 작성하면 :
if(/* some condition */)
dummy1();
else
dummy2();
호출 체인은 런타임 조건에 따라 다릅니다. 맞다면 콜 체인은 다음과 같습니다.
dummy1 --> fun()
조건이 거짓 인 경우 :
dummy2 --> fun()
fun
두 경우 모두 외부 범위 는 발신자 및 발신자의 발신자 등입니다 .
C 언어는 중첩 함수 나 동적 범위 지정을 허용하지 않습니다.
JavaScript
. 따라서 이것이 허용되는 답변으로 표시되어서는 안된다고 생각합니다. JS에서 구체적으로 어휘 범위가 다릅니다
for
루프 내부 가 일반적인 문제입니다. 자바 스크립트에 대한 어휘 범위 만 ES6 않는 기능 수준에 let
또는 const
사용됩니다.
가장 짧은 정의를 시도해 보겠습니다.
어휘 범위 지정 은 중첩 함수에서 변수 이름을 확인하는 방법을 정의합니다. 내부 함수에는 상위 함수가 반환 된 경우에도 상위 함수의 범위가 포함 됩니다.
그것이 전부입니다!
var scope = "I am global";
function whatismyscope(){
var scope = "I am just a local";
function func() {return scope;}
return func;
}
whatismyscope()()
위의 코드는 "나는 단지 로컬입니다"를 반환합니다. "나는 글로벌입니다"를 반환하지 않습니다. func () 함수는 whatismyscope 함수의 범위에 속하는 원래 정의 된 위치를 계산하기 때문입니다.
그것이 호출되는 것이 무엇이든 (글로벌 범위 / 다른 함수 내에서도) 귀찮게하지 않을 것입니다. 그래서 내가 글로벌 인 글로벌 범위 값이 인쇄되지 않습니다.
이를 "어휘 범위 지정"이라고합니다. 여기서 JavaScript 정의 안내서에 따르면 " 함수를 정의 할 때 적용되었던 스코프 체인을 사용하여 함수가 실행됩니다 ".
어휘 범위는 매우 강력한 개념입니다.
도움이 되었기를 바랍니다..:)
범위는 기능, 변수 등을 사용할 수있는 영역을 정의합니다. 예를 들어 변수의 가용성은 컨텍스트 내에서 정의됩니다. 함수, 파일 또는 객체가 정의되어 있다고합시다. 일반적으로 이러한 로컬 변수를 호출합니다.
어휘 부분은 소스 코드를 읽지 않고 범위를 파생시킬 수 있음을 의미합니다.
어휘 범위는 정적 범위라고도합니다.
동적 범위는 정의 후 어디서나 호출하거나 참조 할 수있는 전역 변수를 정의합니다. 대부분의 프로그램 언어의 전역 변수가 어휘 범위에 있더라도 전역 변수라고도합니다. 이는 변수가이 컨텍스트에서 사용 가능하다는 코드를 읽음으로써 파생 될 수 있음을 의미합니다. 아마도 instatiation 또는 정의를 찾기 위해 uses 또는 contains 절을 따라야 할 수도 있지만 코드 / 컴파일러는이 위치의 변수에 대해 알고 있습니다.
반면에 동적 범위 지정에서는 먼저 로컬 함수를 검색 한 다음 로컬 함수를 호출 한 함수를 검색 한 다음 해당 함수를 호출 한 함수 등을 호출 스택에서 검색합니다. "동적"은 주어진 함수가 호출 될 때마다 호출 스택이 다를 수 있으므로 함수가 호출되는 위치에 따라 다른 변수에 부딪 칠 수 있다는 점에서 변경을 나타냅니다. ( 여기 참조 )
동적 범위에 대한 흥미로운 예를 보려면 여기를 참조 하십시오 .
델파이 / 오브젝트 파스칼의 예제
델파이는 어휘 범위를 가지고 있습니다.
unit Main;
uses aUnit; // makes available all variables in interface section of aUnit
interface
var aGlobal: string; // global in the scope of all units that use Main;
type
TmyClass = class
strict private aPrivateVar: Integer; // only known by objects of this class type
// lexical: within class definition,
// reserved word private
public aPublicVar: double; // known to everyboday that has access to a
// object of this class type
end;
implementation
var aLocalGlobal: string; // known to all functions following
// the definition in this unit
end.
델파이가 동적 범위에 가장 가까운 것은 RegisterClass () / GetClass () 함수 쌍입니다. 사용 방법은 여기를 참조 하십시오 .
RegisterClass ([TmyClass])가 특정 클래스를 등록하기 위해 호출 된 시간은 코드를 읽음으로써 예측할 수 없습니다 (사용자가 호출 한 버튼 클릭 메소드에서 호출 됨). GetClass ( 'TmyClass')를 호출하는 코드는 결과 또는 아닙니다. RegisterClass () 호출은 GetClass ()를 사용하여 어휘 범위 내에있을 필요는 없습니다.
동적 범위의 또 다른 가능성 은 델파이 2009의 익명 메소드 (클로저)입니다. 호출 함수의 변수를 알고 있기 때문입니다. 재귀 적으로 호출 경로를 따르지 않으므로 완전히 동적이지 않습니다.
@Arak과 같은 사람들의 모든 기능을 갖춘 언어에 구애받지 않는 답변을 좋아합니다. 이 질문은 JavaScript 로 태그 되었으므로이 언어에 매우 특정한 메모를 작성하고 싶습니다.
JavaScript에서 범위를 지정하기위한 선택은 다음과 같습니다.
var _this = this; function callback(){ console.log(_this); }
callback.bind(this)
JavaScript 에는 실제로 동적 범위 가 없다는 점은 주목할 가치가 있습니다. .bind
조정this
키워드를 가깝지만 기술적으로는 다릅니다.
다음은 두 가지 방법을 모두 보여주는 예입니다. 콜백 범위 지정 방법에 대한 결정을 할 때마다 약속, 이벤트 핸들러 등에 적용됩니다.
다음은 Lexical Scoping
JavaScript에서 콜백 이라는 용어 입니다.
var downloadManager = {
initialize: function() {
var _this = this; // Set up `_this` for lexical access
$('.downloadLink').on('click', function () {
_this.startDownload();
});
},
startDownload: function(){
this.thinking = true;
// Request the file from the server and bind more callbacks for when it returns success or failure
}
//...
};
범위를 정하는 또 다른 방법은 다음을 사용하는 것입니다 Function.prototype.bind
.
var downloadManager = {
initialize: function() {
$('.downloadLink').on('click', function () {
this.startDownload();
}.bind(this)); // Create a function object bound to `this`
}
//...
이 방법들은 내가 아는 한 행동 상 동일합니다.
bind
은 범위에 영향을 미치지 않습니다.
IBM 은이를 다음과 같이 정의합니다.
선언이 적용되는 프로그램 또는 세그먼트 단위의 부분. 루틴에 선언 된 식별자는 해당 루틴과 모든 중첩 루틴 내에 알려져 있습니다. 중첩 루틴이 동일한 이름의 항목을 선언하면 중첩 루틴에서 외부 항목을 사용할 수 없습니다.
예 1 :
function x() {
/*
Variable 'a' is only available to function 'x' and function 'y'.
In other words the area defined by 'x' is the lexical scope of
variable 'a'
*/
var a = "I am a";
function y() {
console.log( a )
}
y();
}
// outputs 'I am a'
x();
예 2 :
function x() {
var a = "I am a";
function y() {
/*
If a nested routine declares an item with the same name,
the outer item is not available in the nested routine.
*/
var a = 'I am inner a';
console.log( a )
}
y();
}
// outputs 'I am inner a'
x();
어휘 범위 는 중첩 된 함수 그룹 에서 내부 함수가 상위 범위의 변수 및 기타 자원에 액세스 할 수 있음을 의미합니다 . 이것은 자식 함수가 부모의 실행 컨텍스트에 어휘 적으로 묶여 있음을 의미합니다. 어휘 범위는 때로는 정적 범위 라고도합니다 .
function grandfather() {
var name = 'Hammad';
// 'likes' is not accessible here
function parent() {
// 'name' is accessible here
// 'likes' is not accessible here
function child() {
// Innermost level of the scope chain
// 'name' is also accessible here
var likes = 'Coding';
}
}
}
어휘 범위에 대해 알 수있는 것은 앞으로 작동한다는 것입니다. 즉, 하위 실행 컨텍스트에서 이름에 액세스 할 수 있습니다. 그러나 부모에게 뒤로 작동하지 않으므로 부모가 변수에 likes
액세스 할 수 없습니다.
이것은 또한 다른 실행 컨텍스트에서 동일한 이름을 가진 변수가 실행 스택의 맨 위에서 아래로 우선한다는 것을 알려줍니다. 가장 안쪽의 함수 (실행 스택의 최상위 컨텍스트)에서 다른 변수와 유사한 이름을 가진 변수가 우선 순위가 높습니다.
여기 에서 가져옵니다 .
간단한 언어에서 어휘 범위는 스코프 외부에서 정의 된 변수이거나 스코프 내에서 스코프를 자동으로 사용할 수 있으므로이를 전달할 필요가 없습니다.
예:
let str="JavaScript";
const myFun = () => {
console.log(str);
}
myFun();
// 출력 : JavaScript
bind
. 그들과 함께, bind
더 이상 필요하지 않습니다. 이 변경 확인에 대한 자세한 내용은 stackoverflow.com/a/34361380/11127383
어휘 및 동적 범위 지정 을 둘러싼 대화에는 중요한 부분이 있습니다. 범위 가 지정된 변수 의 수명 에 대한 명확한 설명 또는 변수에 액세스 할 수있는 경우 .
동적 범위 지정은 전통적으로 우리가 생각하는 방식으로 "전역"범위 지정에 매우 느슨하게 대응합니다 (두 가지를 비교 한 이유는 이미 언급 되었기 때문입니다. 특히 링크 된 기사의 설명이 마음에 들지 않습니다. ); 링크 된 기사에 따르면 "... [it]는 전역 범위 변수를 대체하는 데 유용합니다."
그래서 일반 영어로 두 범위 지정 메커니즘 사이의 중요한 차이점은 무엇입니까?
어휘 범위 지정은 위의 답변 전반에 걸쳐 매우 잘 정의되어 있습니다. 어휘 범위 변수는 정의 된 함수의 로컬 수준에서 사용 가능하거나 액세스 가능합니다.
그러나 OP의 초점이 아니기 때문에 동적 범위 지정은 많은 관심을받지 못했으며 수신 된 관심은 아마도 조금 더 필요할 것입니다 (다른 답변에 대한 비판이 아니라 오히려 "오, 그 대답은 우리가 조금 더 있기를 바랐다 "). 여기 조금 더 있습니다 :
동적 범위 지정은 함수 호출 기간 동안 또는 함수가 실행되는 동안 큰 프로그램에서 변수에 액세스 할 수 있음을 의미합니다. 실제로 Wikipedia는 실제로 두 가지 의 차이점에 대한 설명으로 훌륭하게 작동합니다 . 난독 화하지 않도록 동적 범위 지정을 설명하는 텍스트는 다음과 같습니다.
... [I] n 동적 범위 지정 (또는 동적 범위) 변수 이름의 범위가 특정 함수이면 해당 범위는 함수가 실행되는 시간입니다. 함수가 실행되는 동안 변수 이름이 존재합니다. 변수에 바인딩되어 있지만 함수가 반환 된 후 변수 이름이 존재하지 않습니다.
어휘 범위는 함수가 함수가 정의 된 컨텍스트에서 변수를 찾고 해당 범위의 바로 범위에서 변수를 찾지 않음을 의미합니다.
자세한 내용을 원한다면 Lisp 에서 어휘 범위가 어떻게 작동하는지 살펴보십시오 . Kyle Linin이 Common Lisp의 Dynamic 및 Lexical 변수에서 선택한 답변 은 여기의 답변보다 훨씬 명확합니다.
우연히도 나는 이것에 대해 Lisp 클래스에서만 배웠으며 JavaScript에도 적용됩니다.
Chrome 콘솔 에서이 코드를 실행했습니다.
// JavaScript Equivalent Lisp
var x = 5; //(setf x 5)
console.debug(x); //(print x)
function print_x(){ //(defun print-x ()
console.debug(x); // (print x)
} //)
(function(){ //(let
var x = 10; // ((x 10))
console.debug(x); // (print x)
print_x(); // (print-x)
})(); //)
산출:
5
10
5
JavaScript의 어휘 범위는 함수 외부에 정의 된 변수가 변수 선언 후 정의 된 다른 함수 내에서 액세스 할 수 있음을 의미합니다. 그러나 그 반대는 사실이 아닙니다. 함수 내부에 정의 된 변수는 해당 함수 외부에서 액세스 할 수 없습니다.
이 개념은 JavaScript에서 클로저에 많이 사용됩니다.
아래 코드가 있다고 가정 해 봅시다.
var x = 2;
var add = function() {
var y = 1;
return x + y;
};
이제 add ()->를 호출하면 3이 인쇄됩니다.
따라서 add () 함수는 x
메소드 함수 add 전에 정의 된 전역 변수에 액세스합니다 . 이것은 JavaScript의 어휘 범위로 인해 호출됩니다.
add()
주어진 코드 스 니펫 바로 다음에 호출 된 함수는 3을 인쇄합니다. 어휘 범위 지정은 단순히 함수가 로컬 컨텍스트 외부의 전역 변수에 액세스 할 수 있음을 의미하지는 않습니다. 따라서 예제 코드는 어휘 범위 지정의 의미를 보여주는 데 실제로 도움이되지 않습니다. 코드에서 어휘 범위를 표시하려면 카운터 예제 또는 코드의 다른 가능한 해석에 대한 설명이 필요합니다.
어휘 범위는 실행 스택의 현재 위치에서 볼 수있는 식별자 (예 : 변수, 함수 등)의 어휘를 나타냅니다.
- global execution context
- foo
- bar
- function1 execution context
- foo2
- bar2
- function2 execution context
- foo3
- bar3
foo
과 bar
그들은 세계이기 때문에 가능한 식별자의 사전 내에서 항상.
때 function1
실행되는, 그것의 사전에 액세스 할 수있다 foo2
, bar2
, foo
,와 bar
.
언제 function2
실행되고, 그것의 사전에 액세스 할 수있는 foo3
, bar3
, foo2
, bar2
, foo
, 및 bar
.
글로벌 및 / 또는 외부 함수가 내부 함수 식별자에 액세스 할 수없는 이유는 해당 함수의 실행이 아직 발생하지 않았으므로 해당 식별자가 메모리에 할당되지 않았기 때문입니다. 또한 내부 컨텍스트가 실행되면 실행 스택에서 제거되어 모든 식별자가 가비지 수집되어 더 이상 사용할 수 없음을 의미합니다.
마지막으로, 중첩 된 실행 컨텍스트가 항상 상위 실행 컨텍스트에 액세스 할 수 있고 따라서 더 큰 식별자 사전에 액세스 할 수있는 이유입니다.
보다:
위의 정의를 단순화하는 데 도움을 주신 @ robr3rd 에게 특별한 감사를드립니다 .
이 질문에 대해 한 걸음 물러나 더 큰 해석 프레임 워크 (프로그램 실행)에서 범위 지정 역할을 살펴봄으로써 얻을 수있는 다른 각도가 있습니다. 다시 말해, 언어에 대한 인터프리터 (또는 컴파일러)를 구축 중이고 프로그램 및 일부 입력에 따라 출력 계산을 담당했다고 가정하십시오.
해석에는 다음 세 가지를 추적해야합니다.
상태-즉 힙 및 스택의 변수 및 참조 메모리 위치
해당 상태에서의 작업, 즉 프로그램의 모든 코드 줄
환경 특정되는 동작이 실행 - 즉, 투영 상태로 동작합니다.
인터프리터는 프로그램의 첫 번째 코드 라인에서 시작하여 환경을 계산하고 해당 환경에서 라인을 실행하며 프로그램 상태에 미치는 영향을 캡처합니다. 그런 다음 프로그램의 제어 흐름에 따라 다음 코드 줄을 실행하고 프로그램이 끝날 때까지 프로세스를 반복합니다.
모든 작업에 대한 환경을 계산하는 방법은 프로그래밍 언어로 정의 된 공식 규칙 집합을 통하는 것입니다. "바인딩"이라는 용어는 프로그램의 전체 상태를 환경의 값에 매핑하는 것을 설명하는 데 자주 사용됩니다. "전체 상태"는 전역 상태를 의미하는 것이 아니라 실행의 모든 시점에서 도달 가능한 모든 정의의 합계를 의미합니다.
이것은 범위 지정 문제가 정의되는 프레임 워크입니다. 이제 옵션의 다음 부분으로 넘어갑니다.
이것은 동적 범위 지정 의 요지이며 , 코드가 실행되는 환경은 실행 컨텍스트에 의해 정의 된 프로그램의 상태에 바인딩됩니다.
즉, 어휘 범위 를 사용하면 코드에서 보는 환경이 블록 또는 함수와 같이 언어로 명시 적으로 정의 된 범위와 연관된 상태에 바인딩됩니다.
고대의 질문이지만 여기에 내가 가지고 있습니다.
어휘 (정적) 범위는 소스 코드 에서 변수의 범위를 나타냅니다 .
JavaScript와 같은 언어에서 함수를 전달하고 기타 객체에 첨부하고 다시 첨부 할 수있는 언어에서는 해당 범위가 당시 함수를 호출하는 사람에 따라 다르지만 그렇지 않습니다. 그런 식으로 범위를 변경하면 동적 범위가되고 JavaScript는 this
객체 참조를 제외하고는 그렇게하지 않습니다 .
요점을 설명하려면 :
var a='apple';
function doit() {
var a='aardvark';
return function() {
alert(a);
}
}
var test=doit();
test();
이 예에서 변수 a
는 전역 적으로 정의되었지만 doit()
함수 에는 음영 처리되어 있습니다. 이 함수는 다른 함수를 반환합니다.이 함수는 a
자체 범위를 벗어난 변수에 의존합니다 .
당신이 실행하는 경우 사용되는 값입니다 찾기 것 aardvark
,하지 apple
가의 범위에 있지만, 이는 test()
기능, 원래의 함수의 어휘 범위에 있지 않습니다. 즉, 사용 된 범위는 함수가 실제로 사용되는 범위가 아니라 소스 코드에 나타나는 범위입니다.
이 사실은 성가신 결과를 초래할 수 있습니다. 예를 들어, 함수를 개별적으로 구성하는 것이 더 쉬운 것으로 결정한 다음 이벤트 핸들러와 같이 시간이 오면이를 사용할 수 있습니다.
var a='apple',b='banana';
function init() {
var a='aardvark',b='bandicoot';
document.querySelector('button#a').onclick=function(event) {
alert(a);
}
document.querySelector('button#b').onclick=doB;
}
function doB(event) {
alert(b);
}
init();
<button id="a">A</button>
<button id="b">B</button>
이 코드 샘플은 각각 하나를 수행합니다. 어휘 범위로 인해 button A
은 내부 변수를 사용하지만 button B
은 그렇지 않습니다. 당신이 원했던 것보다 더 많이 중첩 함수를 만들 수 있습니다.
그런데 두 예제 모두에서 포함 함수 함수가 과정을 실행하더라도 내부 어휘 범위 변수는 지속됨을 알 수 있습니다. 이것을 closure 라고 하며 외부 함수가 완료된 경우에도 중첩 함수가 외부 변수에 액세스하는 것을 나타냅니다. JavaScript는 이러한 변수가 더 이상 필요하지 않은지 여부를 판단 할 수있을 정도로 똑똑해야하며 그렇지 않은 경우 가비지 수집 할 수 있습니다.
나는 보통 예를 들어 배우고 여기 약간의 것이 있습니다.
const lives = 0;
function catCircus () {
this.lives = 1;
const lives = 2;
const cat1 = {
lives: 5,
jumps: () => {
console.log(this.lives);
}
};
cat1.jumps(); // 1
console.log(cat1); // { lives: 5, jumps: [Function: jumps] }
const cat2 = {
lives: 5,
jumps: () => {
console.log(lives);
}
};
cat2.jumps(); // 2
console.log(cat2); // { lives: 5, jumps: [Function: jumps] }
const cat3 = {
lives: 5,
jumps: () => {
const lives = 3;
console.log(lives);
}
};
cat3.jumps(); // 3
console.log(cat3); // { lives: 5, jumps: [Function: jumps] }
const cat4 = {
lives: 5,
jumps: function () {
console.log(lives);
}
};
cat4.jumps(); // 2
console.log(cat4); // { lives: 5, jumps: [Function: jumps] }
const cat5 = {
lives: 5,
jumps: function () {
var lives = 4;
console.log(lives);
}
};
cat5.jumps(); // 4
console.log(cat5); // { lives: 5, jumps: [Function: jumps] }
const cat6 = {
lives: 5,
jumps: function () {
console.log(this.lives);
}
};
cat6.jumps(); // 5
console.log(cat6); // { lives: 5, jumps: [Function: jumps] }
const cat7 = {
lives: 5,
jumps: function thrownOutOfWindow () {
console.log(this.lives);
}
};
cat7.jumps(); // 5
console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}
catCircus();
이 주제는 내장 bind
함수와 밀접한 관련이 있으며 ECMAScript 6 화살표 함수 에서 소개되었습니다 . 우리가 사용하고 싶었던 모든 새로운 "클래스"(실제로 함수) 메소드 bind
에 대해 스코프에 액세스하려면이 작업을 수행해야 했기 때문에 정말 성가신 일이었습니다 .
기본적으로 JavaScript는 this
on 함수 의 범위를 설정하지 않습니다 ( 컨텍스트를 on으로 설정하지 않음 this
). 기본적으로 원하는 컨텍스트 를 명시 적으로 말해야 합니다.
화살표 기능 자동 소위 도착 어휘 범위 (그것의 함유 블록의 변수의 정의에 액세스 할 수있는). 사용시 화살표 기능을 자동으로 결합 this
화살표 기능은 처음에 정의 된 장소, 및 문맥 이러한 화살표 함수는 그 블록이 포함된다.
아래의 가장 간단한 예에서 실제로 어떻게 작동하는지 확인하십시오.
화살표 이전 함수 (기본적으로 어휘 범위 없음) :
const programming = {
language: "JavaScript",
getLanguage: function() {
return this.language;
}
}
const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined
const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"
화살표 기능 사용 (기본적으로 어휘 범위) :
const programming = {
language: "JavaScript",
getLanguage: function() {
return this.language;
}
}
const arrowFunction = () => {
console.log(programming.getLanguage());
}
arrowFunction(); // Output: "JavaScript"