>  기사  >  웹 프론트엔드  >  JavaScript 객체 모델 실행 model_javascript 기술

JavaScript 객체 모델 실행 model_javascript 기술

WBOY
WBOY원래의
2016-05-16 18:18:39793검색
데이터 유형
기본 데이터 유형
기본 데이터 유형은 JS 언어의 가장 낮은 구현입니다.
간단한 숫자 유형: 정의되지 않음, Null, 부울, 숫자 및 문자열. 여기서 설명하는 영어 단어는 데이터 유형의 이름만을 참조할 뿐 JS의 전역 개체 N, Boolean, Number, String 등을 구체적으로 참조하지 않는다는 점에 유의하세요. 이들 사이의 개념적 차이는 상대적으로 큽니다.
객체: 값이 단순한 숫자 유형, 객체 또는 함수인 정렬되지 않은 속성 모음입니다. 위와 마찬가지로 여기서 개체는 전역 개체 개체를 구체적으로 참조하지 않습니다.
함수: 함수는 객체의 유형입니다. 구현 시 내부 속성 [[Class]] 값은 "Function"이며 객체의 내부 속성 메서드 외에 [[Construct]], [ [Call]] 및 [[Scope]]와 같은 내부 특성도 있습니다. 함수 호출로서의 함수 처리 메커니즘은 생성자의 처리 메커니즘과 다릅니다(new 키워드를 사용하여 인스턴스 객체 생성)(Function 객체 제외). 내부 메서드 [[Construct]]는 논리를 생성자로 구현하는 데 사용됩니다. [[Call]] 메소드는 Logic을 함수 호출로 구현합니다. 위와 마찬가지로 여기서 함수는 전역 객체 Function을 구체적으로 참조하지 않습니다.
함수는 JS의 프로토타입 언어에서 객체지향 언어의 클래스로 볼 수 있으며, 객체 인스턴스를 구성하는 데 사용할 수 있습니다. 함수는 클래스로 볼 수 있으므로 각 함수는 확장 데이터 유형으로 볼 수 있습니다.

내장 데이터형(내장 객체)
함수: 함수형의 사용자 인터페이스.
객체: 객체 유형의 사용자 인터페이스입니다.
부울, 숫자, 문자열: 이러한 세 가지 간단한 숫자 유형에 대한 개체 래퍼입니다. 개체 래핑은 개념적으로 C#의 Box/Unbox와 유사합니다.
Date, Array, RegExp: 여러 내장 확장 데이터 유형으로 간주될 수 있습니다.

우선 Function, Object, Boolean, Number, String, Date, Array, RegExp 등은 모두 JavaScript 언어의 내장 객체라고 할 수 있습니다. 예를 들어 NumberinstanceofFunction은 true입니다. NumberinstanceofObject는 true입니다. 이런 의미에서 사용자 정의 함수와 동일하게 처리될 수 있습니다.
둘째, 각각은 데이터 유형을 나타낼 수 있으며 이는 기본 코드 또는 내장 JS 코드를 사용하여 JS 엔진에 의해 구현되며 이러한 내장 데이터 유형을 조작하기 위해 개발자에게 노출되는 인터페이스입니다. 이런 의미에서 이는 그 뒤에 숨겨진 특정 구현 메커니즘이 있는 추상적인 개념입니다.
숫자, 함수 등의 단어를 언급할 때마다 위의 두 가지 상황 중 하나로 빠르게 머릿속에서 예시해야 합니다.

데이터 유형 구현 모델 설명
JavaScript 객체 모델 실행 model_javascript 기술
빌드인 *** 데이터 구조: JS 내부에서 *** 유형을 구현하는 데 사용되는 데이터 구조를 말합니다. . 이러한 구조는 기본적으로 우리가 직접 접근할 수 없습니다.
빌드인 *** 객체: JS에 내장된 숫자, 문자열, 부울 및 기타 객체를 의미하며 JS가 내부적으로 구현된 데이터 유형을 개발자에게 공개하는 인터페이스입니다.
빌드인 *** 생성자: JS에 내장된 일부 생성자를 말하며 해당 유형의 객체 인스턴스를 생성하는 데 사용됩니다. 예를 들어, 다음 방법을 사용하여 이러한 함수 개체에 액세스할 수 있습니다.
코드 복사 코드는 다음과 같습니다.

//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
//내장 번호 생성자에 액세스
var number = new Number(123) ;
var numConstructor1 = number.constructor; //또는
var numConstructor2 = new Object(123).constructor;
//numConstructor1과 numConstructor2는 모두 내장 Number 생성자입니다. >numConstructor1 == numConstructor2 //결과: true
//내장 객체 생성자에 액세스
var objConstructor1 = {}.constructor; //또는
var objConstructor2 = new Object().constructor; 🎜>// objConstructor1과 objConstructor2는 모두 내장 객체 생성자입니다.
objConstructor1==objConstructor2 //result: true


구체적인 구현 측면에서 두 항목 사이에 상관 관계가 있을 수도 있습니다. 위 그림의 가로 방향, 예를 들어 build-In 데이터 구조 및 생성자의 경우 Function, Date, Array, RegExp 등은 모두 Object의 구조를 상속하여 구현할 수 있지만 이는 특정 구현과 관련된 문제입니다. .

단순 숫자 유형의 객체화에 대해
다음 설명은 숫자를 예로 들어 Boolean, String 및 Number의 세 가지 단순 숫자 유형에 적용할 수 있습니다.
JS 사양 요구사항: 기본 데이터 유형을 직접 반환하려면 var num1=123;과 같은 코드를 사용하세요. 즉, 반환된 객체는 Number 및 Object 유형에서 파생되지 않습니다. 키워드를 사용하여 Number 유형을 반환합니다. 예를 들어 var num2=new Number(123); num2 instanceof Number는 true입니다.
번호를 함수로 호출하고, 반환 결과를 단순 숫자형으로 변환합니다. 테스트 코드는 다음과 같습니다.


코드를 복사하세요 코드는 다음과 같습니다

//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
var num1 = new Number(123); //Number 및 Object에서 파생된 num1
num1 인스턴스of Number //결과: true
num1 인스턴스of Object //결과: true
//num1을 Number 유형에서 기본 유형으로 변환하므로 더 이상 숫자 또는 객체의 인스턴스
num1 = Number(num1);
num1 인스턴스of 숫자 //결과: false
num1 인스턴스of 객체 //결과: false
var num2 = 123; //num2는 기본 유형입니다.
num2 인스턴스of Number //결과: false
num2 인스턴스of Object //결과: false

간단한 숫자 유형을 얻었지만 Object와 해당 유형의 모든 속성 및 메서드를 포함하여 여전히 JS 객체처럼 보입니다. 기본적으로 사용상의 차이점은 인스턴스 오브의 테스트 결과입니다. .

프로토타입 상속
프로토타입
각 개체에는 [[Prototype]]이라는 내부 속성이 있으며, 해당 값은 null 또는 다른 개체입니다. 함수 객체에는 내부 [[Prototype]] 속성이 아닌 명시적인 프로토타입 속성이 있습니다. 다양한 JS 엔진 구현자는 내부 [[Prototype]] 속성에 임의의 이름을 지정하고 JS 엔진 내에서만 사용되도록 가시성을 설정할 수 있습니다. 내부 [[Prototype]]은 JS 코드에서 액세스할 수 없지만(FireFox에서 액세스할 수 있으며 Mozilla가 공개하기 때문에 이름은 __proto__입니다) 테스트를 위해 객체의 isPrototypeOf() 메서드를 사용할 수 있습니다. 프로토타입 체인에서 판단이 수행되는 동안 전체에 걸쳐 사용됩니다.
obj.propName을 사용하여 객체의 속성에 액세스하는 경우 아래 단계를 따르세요(obj의 내부 [[Prototype]] 속성 이름이 __proto__라고 가정).
obj에 propName 속성이 있는 경우 속성 값, 그렇지 않은 경우
2. obj.__proto__가 null이면 정의되지 않은 값을 반환하고, 그렇지 않으면
3. obj.__proto__.propName을 반환합니다.
객체 호출 방법은 속성 검색 프로세스에 액세스하는 것과 동일합니다. 객체 메소드의 기능은 객체의 속성 값이기 때문입니다.
팁: 위 단계는 3단계에서 obj.__proto__가 또 다른 개체임을 암시합니다. 1, 2, 3단계도 propName 속성을 검색하는 데 사용됩니다.

예를 들어 아래 그림에 표시된 것처럼 object1에는 prop1, prop2, prop3 속성과 fn1, fn2, fn3 메서드가 있습니다. 그림의 점선 화살표는 프로토타입 체인을 나타냅니다.
JavaScript 객체 모델 실행 model_javascript 기술
Prototype을 기반으로 한 상속이자 공유입니다. object1의 fn2 메서드는 object2에서 가져옵니다. 개념적으로 object2는 object3의 fn2 메서드를 재정의합니다.
JavaScript 객체는 모두 프로토타입 체인을 통해 연결되어야 합니다. 최상위 수준은 Object입니다. 즉, 객체는 모두 Object 유형에서 파생됩니다.

C와 같은 객체 지향 언어는 메서드를 전달하기 위해 클래스(추상 유형)를 사용하고 속성을 전달하기 위해 객체(인스턴스화된 객체)를 사용합니다. 본질적인 차이점은 전자는 메모리 구조에 대한 설명을 기반으로 상속을 구현하는 반면, 후자는 특정 메모리 블록을 기반으로 상속을 구현한다는 것입니다.

객체 생성 과정
JS에서는 함수 객체만 클래스 개념을 가지므로 객체를 생성하려면 함수 객체를 사용해야 합니다. 함수 객체 내부에는 [[Construct]] 메소드와 [[Call]] 메소드가 있습니다. [[Construct]]는 객체를 생성하는 데 사용되며, [[Call]]은 함수 호출에만 사용됩니다. new 연산자를 사용할 때.
var obj=new Object(); 내장된 Object 함수 객체를 사용하여 인스턴스화된 객체 obj를 생성합니다. var obj={}; 및 var obj=[]; 이러한 종류의 코드는 JS 엔진에 의한 객체 및 배열 생성 프로세스를 트리거합니다. function fn(){}; var myObj=new fn(); 사용자 정의 유형을 사용하여 인스턴스화된 객체를 생성합니다.

new Fn(args) 생성 과정은 다음과 같습니다. (즉, 함수 객체의 [[Construct]] 메소드가 로직과 객체 생성 과정을 담당합니다. 또한, 함수객체 자체의 생성과정(함수를 정의하거나 Function을 사용하여 함수객체를 생성하는 것을 말한다 등) 역시 다음과 같은 처리 로직을 사용하지만 특별한 곳이 있는데, 이에 대해서는 후술한다.
1. 내장 객체 obj를 생성하고 초기화합니다.
2. Fn.prototype이 Object 유형인 경우 obj의 내부 [[Prototype]]을 Fn.prototype으로 설정합니다. 그렇지 않으면 obj의 [[Prototype ]]이 값을 초기화합니다(예: Object.prototype)
3. obj를 사용하고 args 매개변수를 사용하여 Fn의 내부 [[Call]] 메서드를 호출합니다.
3.1 내부 [[Call]] 메서드는 현재 메서드를 생성합니다. 실행 컨텍스트
3.2 F의 함수 본문 호출
3.3 현재 실행 컨텍스트 삭제
3.4 F의 함수 본문의 반환 값을 반환합니다. F의 함수 본문에 반환 값이 없으면 반환됩니다. 정의되지 않음
4. [[ Call의 반환 값]]이 Object 유형인 경우 이 값이 반환되고, 그렇지 않으면 obj가 반환됩니다.
2단계에서 프로토타입은 에 의해 표시되는 프로토타입 속성을 참조합니다. 객체이고 [[Prototype]]은 객체의 내부 프로토타입 속성(암시적)을 나타냅니다.
객체의 프로토타입 체인을 구성하는 것은 객체의 명시적인 프로토타입 속성이 아닌 내부의 암시적 [[Prototype]]입니다. 표시된 프로토타입은 함수 객체에서만 의미가 있습니다. 위의 생성 과정에서 볼 수 있듯이 함수의 프로토타입은 이러한 방식으로 파생 객체의 암시적 [[Prototype]] 속성에 할당됩니다. 규칙, 파생 객체의 프로토타입 객체, 함수 사이에는 속성과 메소드의 상속/공유 관계만 존재합니다.

코드를 사용하여 확인하세요.
코드 복사 코드는 다음과 같습니다.

//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
function fn(){}
//해당 객체의 암시적 [[Prototype]] 속성 값 fn에서 파생된 것은 fn.prototype
fn.prototype={ attr1:"aaa", attr2:"bbb"}에 할당됩니다.
var obj=new fn();
document.write(obj.attr1 "
"); //결과: aaa
document.write(obj.attr2 "
"); //결과: bbb
document.write(obj instanceof fn); //결과: true
document.write("
");
//여기에서 fn의 프로토타입을 변경하므로 Prototype 알고리즘에 따라 obj는 더 이상 fn의 인스턴스가 아닙니다.
//그러나 이는 obj 및 해당 [[Prototype]] 속성에 영향을 주지 않습니다. , obj에는 여전히 attr1 및 attr2 속성이 있습니다
fn.prototype={};
document.write(obj.attr1 "
"); //결과: aaa
document.write(obj.attr2 "
"); //결과: bbb
document.write(obj instanceof fn); //결과: false关于创建过程返回值的验证:
//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달
function fn(){
//4단계에 따라 위에서 설명한
//새 fn() 작업은 { attr1: 111, attr2: 222 } 객체를 반환하지만 이는 fn의 인스턴스가 아닙니다!
return { attr1: 111, attr2: 222 };
}
fn.prototype={ attr1:"aaa", attr2:"bbb"};
var obj=new fn();
document.write(obj.attr1 "
"); //결과: 111
document.write(obj.attr2 "
"); //결과: 222
document.write(obj 인스턴스offn); //결과: false

做个练习
经过상면적 논리象,cf1, cf2, cf3, cf4, cf5도CF적实例对象。虚线箭头表示隐式Prototype关系,实线箭头表示显示prototype关系。
JavaScript 객체 모델 실행 model_javascript 기술
供参考的实现方案:
复aze代码 代码如下:

//FF2.0, IE7, Opera9.25에서 통과, Safari3.0.4
함수 CF(q1, q2){
this.q1=q1;
this.q2=q2;
}
CF.P1="CF의 P1";
CF.P2="CF의 P2";
function Cfp(){
this.CFP1="CFP1 in Cfp";
}
CF.prototype=new Cfp();
var cf1=새 CF("aaa", "bbb");
document.write(cf1.CFP1 "
"); //결과: Cfp
document.write(cf1.q1 "
")의 CFP1; //결과: aaa
document.write(cf1.q2 "
"); //결과: bbb

본지属性与继承属性
对象过隐式Prototype链能够实现属性과 继承,但prototype也是一丮普个정말 재미있습니다.与以就有了这个本地属性与继承属性问题.
首先看一下设置对象属性时的处理过程。JS설정义了一组속성,사용来描述对象性property, 以表明属性property是否可以는 JavaScript 代码中设值, 被for in枚举等에서 사용됩니다.
obj.propName=value 赋值语句处理步骤如下:
1. 如果propName의 속성设置为不能设值,则返回
2. 如果obj.propName은 则为obj创建一个属性,name称为propName
3. 将obj.propName的值设为value
可以看到,设值过程并不会考虑Prototype链,道理很明显,obj적内부[[Prototype]]是一个实例化的对象,它不仅仅向obj共享属性,还可能向其它对象共享属性,修改它可能影响其它对象。
사용상면CF, 实例对象cf 1具유본지질성q1, q2以及继承属性CFP1,如果执行cf1.CFP1 ="",那么cf1就具有本地属性CFP1了,测试结果如下:
复主代码 码如下:

//FF2.0, IE7, Opera9.25, Safari3.0.4에서 전달됨
var cf1=new CF("aaa", "bbb");
var cf2=새 CF(111, 222);
document.write(cf1.CFP1 "
"); //결과: Cfp의 CFP1
document.write(cf2.CFP1 "
"); //결과: Cfp
의 CFP1//결과적으로 cf1의 로컬 속성이 생성됩니다.
cf1.CFP1="new value for cf1";
//CF.prototype.CFP1에 대한 변경 사항은 cf2에는 영향을 주지만 cf1에는 영향을 미치지 않습니다. cf1에는
//이름이 CFP1인 로컬 속성이 이미 있지만 cf2
CF.prototype에는 그러한 속성이 없기 때문입니다. CFP1="Cfp의 새 값";
document.write(cf1.CFP1 "
"); //결과: cf1의 새 값
document.write(cf2.CFP1 "
"); //결과: Cfp의 새 값

의미 혼란이 있나요?
위의 CF, Cfp 예시 시나리오를 계속 사용하고 있습니다.
Prototype의 메커니즘에 따르면 객체 cf1, cf2 등은 모두 객체 Cfp의 속성과 메서드를 상속한다고 말할 수 있으므로 이들 사이에는 상속 관계가 있다고 해야 합니다. 속성의 상속/공유는 암시적 프로토타입 체인을 따라 작동하므로 상속 관계도 이 체인을 따라 이해되어야 합니다.
다시 instanceOf 연산을 살펴보겠습니다. cf1이 CF의 인스턴스 객체이고, CF가 Cfp의 인스턴스 객체라고 말하는 대신, cf1이 CF에서 상속된다고 해야 할까요? 하지만 CF는 타사 팩토리 역할만 하며 CF와 cf1 사이에는 속성 상속 관계가 없습니다.
CF와 Cfp를 전체적으로 이해하는 것도 무리입니다.

프로토타입은 자바스크립트와 객체지향 개념을 억지로 결합할 필요가 없습니다. 자바스크립트는 제한된 객체지향 기능만을 가지고 있으며, 다른 관점에서 보면 함수형 언어 또는 동적 언어로 간주할 수 있습니다. 따라서 여러 언어 기능을 통합한 간소화된 버전입니다.

객체 모델
우리는 어디에 있습니까?
1. JavaScript의 데이터 유형을 이해하고 Number와 같은 시스템 내장 객체가 여러 ID를 가지고 있음을 이해합니다. a) 객체 자체는 함수 객체입니다. b) 데이터 유형을 나타내며 해당 데이터 유형을 정의하고 작동하는 데 사용할 수 있습니다. c) 그 뒤에는 내부 데이터 구조와 같은 엔진의 내부 구현 메커니즘이 숨겨져 있습니다. 및 다양한 패키지가 JavaScript 객체 등의 생성자가 되었습니다.
2. 프로토타입 메커니즘, 객체가 이를 통해 속성과 메소드를 상속하는 방법, 객체 생성 프로세스 중 JS 엔진 내부에서 프로토타입 관계가 설정되는 방법을 이해합니다.

사용자 정의 함수 개체 자체의 생성 과정을 이해한 후에는 JavaScript 개체 모델에 대한 포괄적인 개요를 얻을 수 있습니다.

함수 객체 생성 과정
JavaScript 코드에서 함수를 정의하거나 함수를 생성하기 위해 Function을 호출할 때 Function 함수는 결국 다음과 유사한 형식으로 호출됩니다. var newFun=Function(funArgs, 펀바디);. 함수 객체를 생성하는 주요 단계는 다음과 같습니다.
1. 내장 객체 fn을 생성합니다
2. fn의 내부 [[Prototype]]을 Function.prototype으로 설정합니다.
3. 논리적 참조 객체 생성 과정의 3단계를 처리하는 내부 구현 메소드인 내부 [[ Call]] 속성
4. 논리적 참조를 처리하는 내부 구현 메소드인 내부 [[Construct]] 속성을 설정합니다. 객체 생성 프로세스의 1,2,3,4 단계
5. fn.length를 funArgs.length로 설정하고, 함수에 매개변수가 없으면 fn.length를 0으로 설정합니다.
6. new Object() 객체 객체 fnProto 생성
7. fnProto.constructor를 fn
으로 설정합니다. 8. fn.prototype을 fnProto
로 설정합니다. 1단계와 6단계의 차이점은 다음과 같습니다. 그 1단계는 단지 Object 객체를 구현하는데 사용되는 내부 데이터 구조(빌드인 객체 구조)를 생성하고 필요한 내부 초기화 작업을 완료하지만, 그 [[Prototype]], [[Call]], [[Construct]] 그리고 다른 속성은 null이거나 내부 초기화 값이어야 합니다. 즉, 어떤 객체도 가리키지 않거나([[Prototype]]과 같은 속성의 경우) 어떤 처리도 포함하지 않는 것으로 이해할 수 있습니다([[Call과 같은 속성의 경우). ]], [[Construct]] 방법). 6단계에서는 앞서 설명한 객체 생성 과정에 따라 새로운 객체를 생성하고 해당 객체의 [[프로토타입]] 등을 설정합니다.
위의 처리 단계에서 알 수 있듯이 함수를 정의할 때마다 해당 함수의 프로토타입은 Object 인스턴스이므로 기본적으로 사용자 정의 함수의 인스턴스 개체를 생성할 때 해당 프로토타입 체인은 Object.prototype을 가리킵니다.
또한 함수의 특별한 특징은 [[Call]]과 [[Construct]] 처리 논리가 동일하다는 것입니다.

JavaScript 객체 모델

JavaScript 객체 모델 실행 model_javascript 기술빨간색 점선은 암시적 프로토타입 체인을 나타냅니다.
이 객체 모델 다이어그램에는 너무 많은 내용이 포함되어 있어 주의 깊게 이해해야 할 부분이 많으며 확인을 위해 몇 가지 테스트 코드를 작성할 수 있습니다. 이 그림을 완전히 이해하고 나면 JavaScript 언어에 대한 이해도가 거의 동일해집니다. 다음은 몇 가지 추가 지침입니다.
1. 그림에서 내장 함수 생성자가 언급된 곳이 여러 군데 있습니다. 이는 동일한 개체이며 테스트하고 확인할 수 있습니다.

코드 복사 코드는 다음과 같습니다.
//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는 자동 가비지 수집을 사용하여 객체 메모리를 확보합니다. 규칙에 따라 주기적으로 확인되며 참조가 없는 경우에만 객체가 해제됩니다. 따라서 위의 코드는 올바르게 실행됩니다.
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.