//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달
Function==Function.constructor / /result: true
Function==Function.prototype.constructor //result: true
Function==Object.constructor //result: true
//Function also Number.constructor, String.constructor , Array.constructor, RegExp.constructor 등과 같습니다.
function fn(){}
Function==fn.constructor //result: true 이는 몇 가지 문제를 보여줍니다. 기능 포인트 시스템의 내장 함수 생성자(내장 함수 생성자)에 함수가 부트스트랩됩니다.
2. 왼쪽 하단에 있는 obj1, obj2...objn 범위는 다음과 같은 코드로 생성된 객체를 나타냅니다. function fn1(){};
이러한 객체는 그렇지 않습니다. 로컬 생성자 메서드가 있지만 프로토타입 체인, 즉 fn.prototype.constructor에서 상속된 생성자 메서드를 가져옵니다. 함수 개체의 생성 프로세스를 보면 그것이 fn 자체라는 것을 알 수 있습니다.
오른쪽 하단에 있는 obj1, obj2...objn 범위는 다음과 같은 코드로 생성된 객체를 나타냅니다. var obj1=new Object() 또는 var obj1=new Number(123) ; 또는 obj1=/w /;등. 따라서 이러한 객체의 프로토타입 체인을 가리키는 것과 프로토타입 체인에서 상속된 생성자의 값(해당 생성자가 내장 Number 생성자인지 내장 Object 생성자인지 등을 참조)은 특정 객체에 따라 달라집니다. 객체 유형. 또한 var obj=new Object(123); 이 방법으로 생성된 객체의 유형은 여전히 Number이며 매개변수 값의 유형에 따라 결정되어야 합니다.
마찬가지로 로컬 생성자가 없지만 프로토타입 체인에서 상속된 생성자 메서드, 즉 내장 *** 생성자를 얻습니다. 구체적인 생성자는 데이터 유형에 따라 결정됩니다.
3. 그림의 Prototype 체인에 대한 추가 설명:
Object.prototype은 전체 체인의 끝점이며 내부 [[Prototype]]은 null입니다.
모든 함수의 프로토타입 체인은 Function.prototype을 가리킵니다.
Function의 Prototype 체인은 Function.prototype을 가리키며, 이는 디자이너가 부트스트랩되도록 Function을 설계했기 때문에 사양에 필요한 것입니다. Function 프로토타입 체인이 이런 방식으로 디자인되면 Function.constructor==Function 및 Function instanceOf Function이 모두 true가 됩니다. 게다가 Function은 이미 최상위 생성자이지만 Function 자체도 무언가에 의해 생성되어야 하므로 부트스트래핑은 의미상 합리적입니다.
Function.prototype의 프로토타입 체인은 사양에서도 요구하는 Object.prototype을 가리킵니다. 먼저 Function.prototype은 Function의 인스턴스 객체(typeof Function.prototype은 Function이라는 것을 알 수 있고, 내부적으로 Prototype 체인이 추가로 설정되어 있기 때문에 instanceOf는 테스트를 통과할 수 없다)이므로 Prototype의 규칙에 따라 Function.prototype의 내부 함수 [ [Prototype]] 값은 Function.prototype 객체여야 합니다. 즉, 프로토타입 체인이 자신을 가리킵니다. 한편으로는 프로토타입 체인에 무한 루프가 생성되고 다른 한편으로는 그 자체가 끝점이 됩니다. 결과적으로 모든 함수 객체는 더 이상 Object에서 파생되지 않습니다. 이 필수 요구 사항을 추가한 후 프로토타입 체인에는 엔드포인트가 하나만 있습니다.
4. Function.prototype은 함수 개체이므로 Function.prototype.prototype이라는 표시된 프로토타입 속성이 있어야 하지만 FireFox에서만 액세스할 수 있고 IE, Opera 또는에서는 액세스할 수 없습니다. 원정 여행. 따라서 그림에는 존재하지 않음을 나타내는 기호가 사용됩니다.
5. 기본적으로 사용자 정의 함수의 [[Prototype]] 값은 Object.prototype입니다. 즉, 암시적 Prototype 체인이 Object.prototype을 가리키므로 그림에 표시됩니다. 그러나 이것이 항상 그런 경우라는 의미는 아닙니다. 사용자 정의 함수의 프로토타입 속성을 설정하면 상황이 달라집니다.
실행 모델
실행 컨텍스트 소개
실행 컨텍스트는 JavaScript 코드가 실행되는 모든 곳에 존재하며 JavaScript 런타임 범위 및 기간 처리 등을 완료하는 데 사용되는 개념 및 메커니즘입니다. 실행 컨텍스트에는 변수 개체, 변수 인스턴스화, 범위/범위 체인 등과 같은 개념이 포함됩니다. 다양한 시나리오/실행 환경에서 처리에 약간의 차이가 있습니다. 이러한 시나리오는 아래에 설명되어 있습니다.
함수 객체는 사용자 정의 함수 객체와 시스템 내장 함수 객체로 구분됩니다. 사용자 정의 함수 객체는 아래 설명된 메커니즘에 따라 처리되지만 내장 함수 객체는 특정 구현과 관련됩니다. , ECMA 사양은 이를 시행합니다. 컨텍스트 처리에 대한 요구 사항은 없습니다. 즉, 일반적으로 이 섹션에 설명된 내용에 적합하지 않습니다.
실행되는 JavaScript 코드는 세 가지 유형으로 나누어지며, 이 세 가지 유형의 처리 차이점은 나중에 설명하겠습니다.
1. 글로벌 코드, 즉 어떤 기능에도 속하지 않는 글로벌 코드입니다. js 파일, HTML 페이지에 포함된 js 코드 등
2. Eval Code는 eval() 함수를 사용해 동적으로 실행되는 JS 코드입니다.
3. 사용자 정의 함수의 함수 본문 JS 코드인 함수 코드입니다.
기본 원리
사용자 정의 함수에서는 매개변수를 전달하고 함수에 지역 변수를 정의할 수 있습니다. 함수 본문 코드에서는 이러한 매개변수와 지역 변수를 사용할 수 있습니다. 그 뒤에 있는 메커니즘은 무엇입니까?
JS 실행 흐름이 함수에 들어가면 JavaScript 엔진은 내부적으로 변수 개체라는 개체를 생성합니다. 함수의 각 매개변수에 해당하는 속성을 Variable Object에 추가합니다. 속성의 이름과 값은 매개변수의 이름과 값과 동일합니다. 함수에서 변수가 선언될 때마다 Variable Object에 속성이 추가됩니다. 이름은 변수 이름이므로 변수에 값을 할당한다는 것은 Variable Object의 해당 속성에 값을 할당한다는 의미입니다. 함수의 매개변수나 지역 변수에 액세스할 때 해당 속성이 Object 변수에서 검색되고 해당 값이 반환됩니다.
일반적으로 Variable Object는 내부 객체이므로 JS 코드에서 직접 접근할 수 없습니다. 사양에는 구현이 필요하지 않으므로 엔진 내부의 데이터 구조일 수도 있습니다.
대략 이렇게 처리하지만 범위의 개념은 그렇게 간단하지 않습니다. 예를 들어 함수 본문에서 전역 변수를 사용할 수도 있고, 함수를 중첩하여 정의하면 상황이 더 복잡해집니다. . 이러한 상황을 어떻게 처리합니까? JavaScript 엔진은 규칙에 따라 다양한 실행 위치에 있는 변수 개체의 연결 목록을 작성하며, 변수에 접근할 때 연결 목록의 첫 번째 변수 개체를 먼저 검색하고, 찾지 못한 경우 계속해서 두 번째 변수를 검색합니다. 검색이 완료될 때까지 이의를 제기하세요. 이것이 범위/범위 체인의 일반적인 개념입니다.
각 측면에 대한 자세한 처리는 다음과 같습니다.
전역 개체
JavaScript 실행 환경에는 HTML의 창 개체와 같은 고유한 전역 개체, 즉 전역 개체가 있어야 합니다. 전역 객체는 JavaScript 런타임에 대한 전역 컨테이너로서의 역할 외에도 호스트 객체에 대한 추가 요구 사항이 없습니다. 여기에는 Math, String, Date,parseInt 및 JavaScript의 기타 내장 전역 개체 및 함수(모두 전역 개체의 속성)가 포함되며 다른 호스트 환경에 필요한 일부 속성도 포함될 수 있습니다.
Variable Object
Variable Object의 기본 개념은 위에서 간략하게 설명했습니다. Variable Object를 생성하고 Variable Object 속성에 매개변수와 로컬 변수를 설정하는 과정을 Variable Instatation이라고 하는데, 이에 대해서는 나중에 Scope Chain과 함께 자세히 설명하겠습니다.
전역 코드
변수 개체는 전역 개체입니다. 이것이 변수 개체의 유일한 특별한 점입니다(내부 접근이 불가능한 개체라는 점을 참고).
var globalVariable = "WWW";
document.write(window.globalVariable); //result: WWW 위 코드는 globalVariable 변수가 정의된 경우 Variable Object 처리 방식으로 실행됩니다. , 이 속성을 전역 개체(예: 창) 개체에 추가하므로 출력은 WWW 값이 됩니다.
Function Code
Variable Object는 Activation Object라고도 합니다(몇 가지 차이점이 있으므로 차이점을 보여주기 위해 스펙에서 새로운 이름을 부여합니다. Global Code/Eval Code에서는 Variable Object라고 합니다. , 함수 코드에서는 변수 객체(Variable Object)라고 합니다.
함수 실행에 들어갈 때마다 새로운 Activation Object 객체가 생성되고, 이후 Argument 객체가 생성되어 Activation Object의 속성으로 설정된 후 Variable Instantiation이 처리됩니다.
함수를 종료하면 활성화 개체가 삭제됩니다(메모리 해제는 아니지만 가비지 수집될 수 있음).
인수 개체의 속성:
길이: 전달된 매개변수의 실제 개수입니다. 참고로 함수 객체 생성 과정을 보면 함수 객체의 길이는 함수 정의 시 필요한 매개변수의 개수입니다.
호출자: 실행된 함수 객체 자체입니다. 예를 들어 재귀 호출이 필요한 경우 함수 개체가 자신을 참조할 수 있도록 하는 것이 목적입니다.
function fnName(...) { ... }는 이렇게 함수를 정의하고, 함수 본문에서 fnName을 사용하여 재귀 호출을 완료할 수 있습니다. var fn=function(...) { ... } 이 방법으로 익명 함수를 정의합니다. 이름을 사용하여 함수 본문에서 자신을 참조할 수 없습니다.
매개변수 목록: 호출자가 실제로 전달한 매개변수 목록입니다. 이 매개변수 목록은 색인을 사용하여 실제 매개변수에 액세스하는 방법을 제공합니다. 변수 인스턴스화는 함수가 선언될 때 지정된 매개변수 목록이 있는 경우 처리 중에 활성화 개체 개체에 속성을 추가합니다. 함수 선언에 매개변수 목록이 제공되지 않거나, 실제 매개변수 개수가 함수 선언에 있는 매개변수 개수와 다른 경우, 각 매개변수는 인수를 통해 접근할 수 있습니다.
인수의 매개변수 목록과 활성화 개체의 매개변수 속성은 동일한 매개변수 개체를 참조합니다(수정된 경우 두 위치에 모두 반영됩니다). 사양에서는 인수가 배열 객체일 것을 요구하지 않습니다. 테스트는 다음과 같습니다.
//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
var 인수Like = { 0: "aaa", 1: 222, 2: "WWW", 길이: 3, 수신자: function () { } };
document.write(argumentsLike[2] "
") //결과: WWW
document.write(argumentsLike[1] "< ;br /> "); //결과: 222
//arguments 속성에 대해 수행할 수 있는 것과 마찬가지로 인수Like를 배열 객체로 변환합니다.
var array = [].slice.apply(argumentsLike );
document.write(배열 인스턴스); //결과: true
document.write("
")
document.write(array.reverse().join ("|") ); //결과: WWW|222|aaa
평가 코드
변수 개체는 eval이 호출될 때 현재 실행 컨텍스트의 변수 개체입니다. eval 함수가 전역 코드에서 호출되면 해당 변수 개체는 전역 개체이고, 함수에서 eval이 호출되면 해당 변수 개체는 함수의 활성화 개체입니다.
//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
function fn(arg){
var innerVar = "함수 내 변수"
eval('
var evalVar = "eval의 변수";
document.write(arg "
")
document.write(innerVar "
"); ') ;
document.write(evalVar)
}
fn("함수 인수");
출력 결과는 다음과 같습니다.
함수에 대한 인수
함수의 변수
평가의 변수
설명: 함수 fn의 매개변수 및 지역 변수는 정의된 평가 호출에서 액세스할 수 있습니다. eval에서는 변수 개체가 동일한 개체이기 때문에 fn 함수에서도 액세스할 수 있습니다.
Scope/Scope Chain
먼저 Scope Chain은 연결리스트/스택과 유사한 구조로, 그 안의 각 요소는 기본적으로 Variable Object/Activation Object입니다.
둘째, 실행 컨텍스트가 있는 곳에는 현재 스코프 체인이 있습니다. 스코프 체인은 실행 컨텍스트의 구체적인 표현이라고 이해할 수 있습니다.
글로벌 코드
스코프 체인에는 전역 개체라는 하나의 개체만 포함됩니다. JavaScript 코드 실행을 시작하기 전에 엔진은 이 범위 체인 구조를 생성합니다.
함수 코드
함수 개체에는 함수가 위치한 범위 체인을 기록하는 데 사용되는 내부 [[Scope]] 속성이 있습니다.
함수 객체를 생성할 때 엔진은 현재 실행 환경의 범위 체인을 Function의 [[Construct]] 메서드에 전달합니다. [[Construct]]는 전달된 Scope Chain과 동일한 내용으로 새로운 Scope Chain을 생성하고 생성된 함수의 내부 [[Scope]] 속성에 할당합니다. 함수 개체 생성 프로세스에 대한 이전 섹션에서 이 프로세스는 4단계와 5단계 사이에 있었습니다.
함수 호출을 시작하면 동일한 함수의 재귀 호출을 포함하여 새로운 범위 체인도 생성됩니다. 이 범위 체인은 함수를 종료할 때 삭제됩니다. 새로 생성된 Scope Chain의 첫 번째 객체는 Activation Object이며, 다음 내용은 내부 [[Scope]]에 저장된 Scope Chain의 내용과 완전히 동일합니다.
Eval Code
실행을 위해 Eval Code를 입력하면 새로운 Scope Chain이 생성되며, 그 내용은 현재 실행 컨텍스트의 Scope Chain과 정확히 동일합니다.
예시 설명
스코프 체인의 원리는 바로 위와 같습니다. 위의 작동 방식을 이해하려면 JS 코드의 실행 및 변수 인스턴스화의 세부 사항을 결합해야 합니다. 아래에서 포괄적으로 설명합니다. 다음은 JavaScript 전역 코드의 일부라고 가정합니다.
var externalVar1= "전역 코드의 변수";
function fn1(arg1, arg2){
var innerVar1="함수 코드의 변수"
function fn2() { return externalVar1 " - " innerVar1 " - " " - " (arg1 arg2); }
return fn2();
}
var externalVar2=fn1(10, 20);
실행과정은 대략 다음과 같습니다.
1. 윈도우 객체인 Global 객체와 윈도우 객체 자체인 Variable 객체를 초기화합니다. 창 개체만 포함하는 범위_1이라고 가정하고 범위 체인 개체를 만듭니다.
2. JS 소스 코드를 스캔하고(소스 코드를 읽으면 어휘 및 구문 분석 과정이 있을 수 있음) 결과에서 정의된 변수 이름과 함수 객체를 얻을 수 있습니다. 스캔 순서에 따라:
2.1 변수 externalVar1을 발견하고, window 객체에 externalVar1 속성을 추가합니다. 값은 정의되지 않습니다.
2.2 함수 fn1의 정의를 발견하고, 이 정의를 사용하여 함수 객체를 생성합니다. 생성 프로세스에 전달된 범위 체인은 range_1 입니다. 이름이 fn1이고 값이 반환된 함수 객체인 window 속성에 결과를 추가합니다. fn1의 내부 [[Scope]]는scope_1입니다. 또한 생성 과정에서는 함수 본문에 있는 JS 코드에 대해 특별한 처리를 수행하지 않는다는 점에 유의하세요. 이는 함수 본문에 있는 JS 코드의 스캔 결과만 함수 개체의 내부 속성에 저장하는 것으로 이해될 수 있습니다. 함수가 실행될 때 처리합니다. 이는 함수 코드, 특히 중첩된 함수 정의의 변수 인스턴스화를 이해하는 데 중요합니다.
2.3 변수 externalVar2를 발견하고 window 객체에 externalVar2 속성을 추가하면 값이 정의되지 않습니다.
3. 값을 "전역 코드의 변수"로 할당합니다.
4. fn1 함수를 실행하고 반환 값을 가져옵니다.
4.1 활성화 개체를 생성합니다(활성화_1이라고 가정). 범위 체인을 생성하고 범위_2의 첫 번째 개체는 활성화_1입니다. 객체는 창 객체입니다(fn1의 [[Scope]], 즉
4.2 프로세스 매개변수 목록에서 가져옴). 활성화_1에 arg1 및 arg2 속성을 각각 값 10과 20으로 설정합니다. 인수 객체를 생성하고 설정한 후 인수를 활성화_1의 속성으로 설정합니다.
4.3 fn1의 함수 본문에서 2단계와 유사한 프로세스를 수행합니다.
4.3.1 변수 innerVar1을 검색하고 innerVar1 속성을 추가합니다. 활성화_1 객체, 값은 정의되지 않았습니다.
4.3.2 함수 fn2의 정의를 발견하고 이 정의를 사용하여 함수 객체를 생성하며 생성 프로세스에 전달된 범위 체인은 범위_2입니다(함수 fn1의 범위 체인은 다음과 같습니다). 현재 실행 컨텍스트의 내용). fn2라는 이름과 반환된 함수 객체의 값을 사용하여 활성화_1의 속성에 결과를 추가합니다. fn2의 내부 [[Scope]]는scope_2입니다.
4.4 innerVar1 할당문을 실행하고 "함수 코드의 변수"에 값을 할당합니다.
4.5 fn2 실행:
4.5.1 활성화 개체를 생성합니다(활성화_2라고 가정). 범위_3의 첫 번째 개체는 활성화_2이고 다음 개체는 활성화_1 및 창이라고 가정합니다. .객체(fn2의 [[Scope]], 즉scope_2에서 가져옴);
4.5.2 프로세스 매개변수 목록. fn2에는 매개변수가 없으므로 인수 객체를 생성하고 이를 활성화_2의 속성으로 설정하면 됩니다.
4.5.3 fn2의 함수 본문에 대해 2단계와 유사한 프로세스를 수행하면 변수 정의 및 함수 선언이 발견되지 않습니다.
4.5.4 함수 본문을 실행합니다. 변수 참조의 경우 범위_3에서 검색합니다. 이 예에서는 innerVar1, arg1 및 arg2가 활성화_1에서 발견됩니다.
4.5.5 범위_3 및 활성화_2를 삭제합니다(가비지 수집 가능함을 의미).
4.5.6 fn2의 반환 값을 반환합니다.
4.6 활성화_1과 범위_2를 삭제합니다.
4.7 결과 반환.
5. 결과를 externalVar2에 할당합니다.
그 외의 경우에는 Scope Chain과 Variable Instantiation도 위 과정과 유사하게 분석할 수 있습니다.
위의 예에 따르면 다음 테스트 코드의 결과를 설명할 수 있습니다.
//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
function fn(obj){
return {
/ /obj에 지역 변수 "outerVar"가 있는지 테스트
존재함: Object.prototype.hasOwnProperty.call(obj, "outerVar"),
//변수 "outerVar"의 값 테스트
value : obj.outerVar
}
var result1 = fn(window);
var externalVar = "WWW"
var result2 = fn(window); >document.write( result1.exists " " result1.value); //result: true 정의되지 않음
document.write("
")
document.write(result2.exists " " result2.value); //result: true WWWresult1이 호출된 경우 externalVar 선언 및 할당 문이 실행되지 않았지만 테스트 결과 창 개체에는 값이 정의되지 않은 로컬 속성인 innerVar이 이미 있습니다. result2의 externalVar에 값이 할당되었으므로 window.outerVar의 값이 이미 존재합니다. 실제 사용 시에는 먼저 사용하지 마시고 정의해 주시기 바랍니다. 그렇지 않으면, 사양에 언급되지 않은 제조사별 구현 방법에 일부 불일치가 발생하기 때문에 문제가 발생할 수 있습니다.
특수 처리
1.(obj) { ... }를 사용하여 이 구문을 구현하는 것은 obj 객체를 현재 범위 체인 앞에 삽입하여 obj가 먼저 검색되는지 확인하는 것입니다. 해당 이름을 가진 속성이 존재합니다. 다른 유사한 것에는 catch 문이 포함됩니다.
2. 이전의 인수 개체에 대한 자세한 설명에서 재귀 함수 호출 지원에 대해 언급했습니다. 위의 내용은 스코프 체인의 작동 원리로 인해 아직 이 현상을 설명할 수 없습니다. 여기에는 특별한 처리가 있기 때문입니다.
이름이 지정된 함수 개체가 생성될 때마다 JavaScript 엔진은 현재 실행 컨텍스트 범위 체인 앞에 개체를 삽입합니다. 이 개체는 새 Object() 메서드를 사용하여 생성되고 범위 체인이 전달됩니다. 함수 생성자 [ [Construct]], 최종 생성된 함수 개체는 [[Scope]] 내부에 이 개체 개체를 포함합니다. 생성 프로세스가 반환된 후 JavaScript 엔진은 함수 이름과 반환된 함수 개체의 값을 사용하여 개체에 속성을 추가한 다음 현재 실행 컨텍스트의 범위 체인에서 이를 제거합니다. 이런 식으로 함수 객체의 범위 체인의 첫 번째 객체는 자신에 대한 참조이며 제거 작업은 함수 객체가 생성된 범위 체인의 복원을 보장합니다.
이 키워드 처리
실행 컨텍스트에 포함된 또 다른 개념은 this 키워드입니다.
글로벌 코드의 this 키워드는 전역 개체입니다. 함수가 호출될 때 this 키워드는 호출자입니다(예: obj1.fn1()). fn1에서 this 개체는 평가 코드의 this 키워드입니다. 현재 실행 컨텍스트 개체의 변수입니다.
함수를 호출할 때 JavaScript는 사용자가 이 키워드의 값, 즉 각 함수가 갖는 호출 및 적용 메서드를 지정할 수 있는 기회를 제공합니다. 예:
fn1.call(obj1, arg1, arg2, ...) 또는 fn1.apply(obj1, argArray)는 모두 obj1을 이 키워드로 사용하여 fn1 함수를 호출하고 실행하며 모든 후속 매개변수는 다음과 같이 사용됩니다. 함수 fn1 매개변수. obj1이 null이거나 정의되지 않은 경우 전역 개체가 이 키워드의 값으로 사용되며, obj1이 개체 유형이 아닌 경우 개체 유형으로 변환됩니다. 유일한 차이점은 Apply를 사용하면 각 매개변수를 배열 형식으로 제공할 수 있는 반면, 호출 메소드는 매개변수를 하나씩 제공해야 한다는 것입니다.
이 방법은 이전 테스트 샘플 코드의 여러 곳에서 사용되었습니다. 예를 들어 window 객체에는 hasOwnProperty 메서드가 없습니다. 또한 Object.prototype.hasOwnProperty.call(window, "propertyName")을 사용하여 로컬 속성이 있는지 테스트할 수도 있습니다.
JavaScript의 클로저
예:
//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
function external(){
var a="aaa"
var b="bbb";
return function(){ return a " " b;
}
var inner=outer();
document.write(inner());outer는 인라인 함수를 반환합니다. 함수는 외부의 지역 변수 a와 b를 사용합니다. 논리적으로 말하면, 외부의 지역 변수는 반환될 때 범위를 벗어나므로 inner() 호출을 사용할 수 없습니다. 이것이 클로저입니다. 즉, 함수 호출이 포함된 함수를 반환하고, 포함된 함수는 닫혀야 하는 외부 함수의 지역 변수, 매개변수 및 기타 리소스를 참조합니다(Close).
스코프 체인에 대한 이전 이해에 따르면 반환된 인라인 함수는 생성 당시 이미 스코프 체인을 보유하고 있다고 설명할 수 있습니다. 비록 외부 반환으로 인해 이러한 개체가 범위 및 수명 범위를 초과하게 됩니다. , JavaScript는 자동 가비지 수집을 사용하여 객체 메모리를 확보합니다. 규칙에 따라 주기적으로 확인되며 참조가 없는 경우에만 객체가 해제됩니다. 따라서 위의 코드는 올바르게 실행됩니다.