다음 예를 살펴보세요.
var a = 'global' ;
(function () {
alert(a);
var a = 'local';
})(); >
여러분 먼저 이 예시를 보시면 어떤 결과가 나올 것 같나요? '글로벌'? 아니면 '현지'인가요? 사실은 그렇지 않습니다. 출력은 정의되지 않았습니다. 내 여담은 단지 이것에 대해 이야기하는 것입니다.
사실 JavaScript 작동 메커니즘을 살펴보면 매우 간단합니다. 우리는 이런 현상을 '선언문'이라고 생각할 수 있다. 하지만 조금 더 깊이 파고들면 더 명확하게 이해할 수 있을 것입니다.
이는 실제로 객체 속성 바인딩 메커니즘과 관련이 있습니다. 모든 JavaScript 함수는 객체이기 때문입니다. 함수에 선언된 변수는 이 개체의 "유사한 속성"으로 간주될 수 있습니다. 객체 속성의 바인딩은 언어에서 "early 바인딩"과 "late 바인딩"으로 구분됩니다.
[초기 바인딩]
은 객체를 인스턴스화하기 전에 객체의 속성과 메서드를 정의하는 것을 의미합니다. 프로그램을 파싱할 때 미리 기계어 코드로 변환해 둘 수 있다. C, Java 등 일반적으로 입력되는 언어는 모두 초기 바인딩 메커니즘을 사용합니다. 그리고 JavaScript는 강력한 형식의 언어가 아닙니다. 이는 "후기 바인딩" 메커니즘을 사용합니다.
【Late Binding】
은 프로그램을 실행하기 전에 객체 유형을 확인할 필요 없이 객체가 속성과 메서드를 지원하는지 여부만 확인한다는 의미입니다. 바인딩하기 전에 페널티 없이 개체에 대해 많은 작업을 수행할 수 있습니다.
위 코드의 '사전 선언' 현상은 '후기 바인딩' 메커니즘으로 설명할 수 있습니다. 함수 범위 내에서 모든 변수는 "늦게 바인딩"됩니다. 즉, 해당 명령문은 최상위 수준입니다. 따라서 위 코드는 다음과 일치합니다.
(function () {
var a;
alert(a);
a = 'local';
})(); >
alert(a) 이전에는 값을 할당하지 않고 a만 선언했습니다. 결과는 상상할 수 있습니다.
RT: 이 기사에서는 JavaScript에서 클래스와 개체를 정의하는 몇 가지 방법에 대해 설명합니다. < - 진술: 다음 내용의 대부분은 "JavaScript 고급 프로그래밍"에서 가져온 것이지만 개인적인 서술 방식은 다릅니다 -- >
【직접 수량 방식】
직접 수량을 사용하여 객체를 구성하는 것이 가장 기본적인 방법입니다. 하지만 단점도 많습니다.
코드 복사
코드는 다음과 같습니다. var Obj = new Object; Obj.name = 'sun'; Obj.showName = function() {
alert('this.name');
}
객체 Obj를 구성합니다. 속성 이름과 showName 메소드가 있습니다. 하지만 또 다른 유사한 객체를 만들고 싶다면 어떻게 해야 할까요? 다시 반복해야 하나요?
안돼! , 특정 유형의 객체를 반환하는 팩토리 함수를 사용하여 구현할 수 있습니다. 공장과 마찬가지로 파이프라인은 우리가 원하는 특정 유형의 결과를 출력합니다.
【팩토리 메소드】
코드 복사
tempObj.showName = function () {
alert(this.name)
return tempObj ;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');
많은 사람들이 이것을 사용하지 않습니다. 팩토리 함수 객체를 구성하는 형태. 그 이유 중 하나는 의미론입니다. new 연산자를 사용하여 구축하는 것만큼 형식적이지 않습니다. 또 다른 더 큰 이유가 있습니다. 왜냐하면 이 팩토리가 객체를 생성할 때마다 새로운 함수 showName()을 생성하기 때문입니다. 즉, 각 객체는 서로 다른 버전을 가지지만 실제로는 동일한 기능을 공유합니다.
어떤 사람들은 팩토리 함수 외부에서 showName을 정의한 다음 속성을 통해 메서드를 지정하여 이 문제를 피할 수 있습니다.
코드 복사
var tempObj = new Object ;
tempObj.name = name;
tempObj를 반환합니다.
}
var obj('obj_one'); obj2 = createObj( 'obj_two')
안타깝게도 이 메소드는 showName() 함수를 객체의 메소드처럼 보이지 않게 만듭니다.
[생성자 방식]
이 방식은 위 팩토리 함수의 첫 번째 문제, 즉 신규 연산자가 없다는 문제를 해결하기 위한 방식이다. 하지만 여전히 두 번째 문제를 해결할 수 없습니다. 살펴 보겠습니다.
function Obj(이름) {
this.name = 이름;
this.showName = function () {
alert(this.name)
}
}
var obj1 = new Obj('obj_one'); 🎜>var obj2 = new Obj('obj_two');
new 연산자가 자동으로 객체를 생성하므로 생성자에서 새 객체를 생성할 필요가 없다는 장점이 있습니다. 실행되며 이를 통해서만 이 개체에 액세스할 수 있습니다. 그래서 우리는 이것을 통해 이 객체에 직접 값을 할당할 수 있습니다. 그리고 반환할 필요도 없습니다. 기본적으로 생성자의 반환 값을 가리키기 때문입니다.
동시에 새로운 키워드를 사용하여 우리가 원하는 객체를 생성하는 것은 좀 더 "격식적"이라는 느낌을 줍니다.
안타깝게도 팩토리 함수와 동일한 메서드 함수를 반복적으로 생성하는 문제는 여전히 해결되지 않습니다.
[프로토타입 방법]
위의 방법들에 비해 이 방법은 메서드 함수가 여러 번 생성되는 문제를 해결한다는 큰 장점이 있습니다. 객체의 프로토타입 속성을 활용합니다. 우리는 객체 인스턴스를 재정의하기 위해 프로토타입을 사용합니다.
var Obj = function () {}
Obj .prototype.name = '나';
Obj.prototype.showName = function () {
alert(this.name)
}
var obj1 = new Obj();
var obj2 = new Obj();
우리는 프로토타입에 의존하여 생성자를 다시 작성합니다. 속성과 메소드 모두 프로토타입 참조를 통해 새로 생성된 객체에 제공됩니다. 한 번 생성되었습니다. 불행하게도 이 방법에는 두 가지 치명적인 문제가 있습니다.
1. 프로토타입은 생성자의 범위 밖에 있기 때문에 객체 생성 시 원하는 속성을 작성할 방법이 없고, 매개변수를 전달하여 객체 생성 시 속성값을 작성할 방법도 없습니다. 값은 개체가 생성된 후에만 재정의될 수 있습니다.
2. 치명적인 문제는 속성이 개체를 가리킬 때 개체가 여러 인스턴스에서 공유된다는 것입니다. 다음 코드를 고려하십시오.
var Obj = function () { }
Obj.prototype.name = '나';
Obj.prototype.flag = new Array('A', 'B')
Obj.prototype.showName = 함수() {
alert(this.name);
}
var obj1 = new Obj()
var obj2 = new Obj()
obj1.flag.push('C') ;
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B,C
예, 플래그 속성이 object 를 가리키면 obj1과 obj2 인스턴스 모두 이를 공유합니다. obj1의 플래그 속성만 변경하더라도 해당 변경 사항은 obj2 인스턴스에서 계속 표시됩니다.
이러한 문제에 직면했을 때, [생성자 방식]과 [프로토타입 방식]을 결합하여 상호보완적으로 만들어야 할지 고민해야 합니다. . .
[생성자와 프로토타입 혼합 방식]
생성자 메서드를 사용해 속성을 생성하고, 프로토타입 메서드를 사용해 메서드를 생성할 수도 있습니다:
var Obj = 함수(이름) {
this.name = 이름
this; .flag = new Array(' A', 'B');
}
Obj.prototype = {
showName : function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj()
obj1.flag.push('C')
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B
이 방법은 프로토타입과 생성자의 장점을 효과적으로 결합한 방법이며 현재 가장 많이 사용되는 방법입니다. 부작용이 가장 적습니다.
그러나 완벽함을 추구하는 일부 사람들은 아직 시각적으로 요구 사항이 충족되지 않아 만족하지 못하는 경우가 있습니다. 프로토타입을 통해 메서드를 만드는 과정은 여전히 시각적으로 인스턴스 메서드처럼 보이지 않기 때문입니다(특히 개발자의 경우). )
따라서 프로토타입을 활성화하고 생성자에 추가하여 생성자를 더욱 시각적으로 통일할 수 있습니다. 이 일련의 과정은 단 한 번의 판단으로 완료될 수 있습니다.
코드 복사 코드는 다음과 같습니다.
var Obj = 함수(이름) {
this.name = 이름;
this.flag = new Array('A', 'B')
if(Obj의 유형) _init == '정의되지 않음') {
Obj.prototype = {
showName : function () {
alert(this.name);
}
Obj._init = true;
}
}
위와 같이 _init를 플래그로 사용하여 프로토타입에 대한 메서드가 생성되었는지 확인합니다. 그렇다면 실행되지 않습니다. 실제로는 본질적인 변화가 없습니다. 메서드는 여전히 프로토타입을 통해 생성됩니다. 유일한 차이점은 이 생성자가 "통합"되어 보인다는 것입니다.
그러나 이 동적 프로토타이핑 방법에는 문제가 있는데, 이는 "JavaScript 고급 프로그래밍"에서 자세히 다루지 않습니다. 첫 번째 개체를 생성하면 개체가 인스턴스화되기 전에 프로토타입이 빌드되지 않으므로 전혀 액세스할 수 없습니다. 따라서 첫 번째 객체는 프로토타입 메서드에 액세스할 수 없습니다. 동시에 이 메서드는 하위 클래스 상속에도 문제가 있습니다.
다음 글에서 해결 방법을 설명하겠습니다.
사실 사용 편의성 측면에서는 이런 판단을 할 필요가 없다고 개인적으로 생각합니다. . . 하하 ^_^