예시 #1: 함수 표현식 식별자가 바깥쪽 범위로 누출됨
예시 #1: 함수 표현식 식별자가 바깥쪽 범위로 누출됨
var f = function g(){}
typeof g; // "function"
이름이 지정된 함수 표현식의 식별자를 바깥쪽 범위에서 사용할 수 없다고 언급한 것을 기억하시나요? JScript는 이에 대한 사양에 동의하지 않습니다. 위의 예는 함수 개체로 해결됩니다. 이는 가장 널리 관찰되는 불일치입니다. 물론 이러한 오염은 전역 범위일 수도 있는 범위를 의도치 않게 오염시킬 수 있다는 점에서 위험합니다. , 추적하기 어려운 버그의 원인이 됩니다.
방금 이름이 지정된 함수 표현식의 식별자는 외부 범위에서 액세스할 수 없다고 언급했습니다. 그러나 JScript는 이와 관련하여 표준을 따르지 않습니다. 위의 예에서 g는 함수 개체입니다. 이는 널리 관찰 가능한 차이입니다. 이런 식으로 주변 범위를 추가 식별자로 오염시킵니다. 이는 아마도 전역 범위일 수 있으며 이는 매우 위험합니다. 물론 이러한 오염은 처리 및 추적이 어려운 버그의 원인일 수 있습니다
예 #2: 명명된 함수 표현식은 함수 선언과 함수 표현식 모두로 처리됩니다.
예 #2: 명명된 함수 표현식 함수 표현식은 둘 다로 처리됩니다 - 함수 선언 및 함수 표현식 이중 처리, 함수 표현식 및 함수 선언
typeof g; // "function"
var f = function g(){};
앞서 설명했듯이 함수 선언은 특정 실행 컨텍스트에서 다른 표현식보다 먼저 구문 분석됩니다. 위의 예는 JScript가 실제로 명명된 함수 표현식을 함수 선언으로 처리하는 방법을 보여줍니다. g를 "실제 선언" 전에 구문 분석하는 것을 볼 수 있습니다.
앞서 설명했듯이 특정 실행 환경에서는 함수 선언이 모든 표현식보다 먼저 해석됩니다. 위의 예는 JScript가 실제로 명명된 함수 표현식을 함수 선언으로 처리한다는 것을 보여줍니다. 실제 진술 이전에 그가 설명하고 있는 것을 볼 수 있다.
다음 예시로 넘어갑니다.
이를 바탕으로 다음 예시를 소개합니다.
예시 #3: 명명된 함수 표현식은 두 개의 DISCTINCT 함수 개체를 생성합니다!
예시 #3: 명명된 함수 표현식은 두 개의 서로 다른 함수 객체를 생성합니다.
var f = function g(){};
f === g; // false
f.expando =
g.expando; / 정의되지 않음
여기서 상황이 흥미로워지고 있습니다. 아니면 완전히 미친 것입니다. 여기서 우리는 두 개의 서로 다른 개체를 처리해야 하는 위험을 보고 있습니다. 그 중 하나를 확장해도 다른 개체는 수정되지 않습니다. 예를 들어 캐싱 메커니즘을 사용하고 f의 속성에 무언가를 저장하기로 결정한 다음 작업 중인 객체와 동일한 객체라고 생각하여 g의 속성으로 액세스하려고 하면 상당히 문제가 될 수 있습니다. 🎜>여기서 상황이 좀 더 흥미로워지거나 완전히 이상해집니다. 여기서 우리는 두 개의 서로 다른 개체를 처리해야 하므로 그 중 하나가 확장되면 다른 개체도 그에 따라 변경되지 않는 위험을 알 수 있습니다. 캐시 메커니즘을 사용하여 f 속성에 무언가를 저장하고 g 속성에서만 액세스하려고 한다면 동일한 객체를 가리킨다고 생각하여 매우 번거로울 것입니다
좀 더 복잡한 것을 살펴보겠습니다.
좀 더 복잡한 예를 살펴보겠습니다.
예 #4: 함수 선언은 순차적으로 구문 분석되고 조건 블록의 영향을 받지 않습니다.
예 #4: 함수 선언은 순차적으로 구문 분석되며 조건 블록의 영향을 받지 않습니다.
var f = function g() {
return 1;
};
if (false) {
f = function g(){
return 2; 🎜>g(); // 2
이와 같은 예는 버그를 추적하기 더욱 어렵게 만들 수 있습니다. 여기서 일어나는 일은 실제로 매우 간단합니다. JScript는 조건부 블록과 독립적입니다. g는 "죽은" if 분기 - function g(){ return 2 }에서 함수로 선언됩니다. 그러면 모든 "일반" 표현식이 평가되고 f에는 새로 할당됩니다. 표현식을 평가할 때 분기가 입력되지 않으면 "죽음"이므로 f는 계속 첫 번째 함수인 function g(){ return 1 }을 참조합니다. f 내에서 g를 호출하면 전혀 관련이 없는 g 함수 개체를 호출하게 됩니다.
이와 같은 예는 버그 추적을 매우 어렵게 만들 수 있습니다. 여기서 문제는 매우 간단합니다. 첫 번째 g는 함수 선언으로 해석되며 JScript의 선언은 조건 블록과 독립적이므로 g는 잘못된 if 분기 함수 g(){ return 2 }에서 함수로 선언됩니다. 그런 다음 일반 표현식이 평가되고 f가 새로 생성된 다른 함수 개체에 할당됩니다. 표현식이 실행되면 if 조건 분기가 입력되지 않으므로 f는 첫 번째 함수 function g(){ return 1 }에 대한 참조로 유지됩니다.이제 주의하지 않고 f 내부에서 g를 호출하면 결국 전혀 관련이 없는 g 함수 개체를 호출하게 된다는 것이 분명해졌습니다.
각기 다른 함수 객체로 인해 발생하는 이 모든 혼란이 인수.callee와 어떻게 비교되는지 궁금할 것입니다. 호출 수신자가 f 또는 g를 참조합니까? 살펴보겠습니다.
이 모든 혼란이 어떻게 발생하는지 궁금할 것입니다. 다른 함수 개체를 사용하여 인수.callee를 비교하면 해당 개체를 인수.callee와 비교한 결과가 어떻게 될까요? 수신자가 f 또는 g를 참조합니까?
var f = function g(){
return [
arguments.callee == f,
arguments.callee == g
];을 살펴보겠습니다. >};
f(); // [true, false]
보시다시피,args.callee는 f 식별자와 동일한 객체를 참조합니다. 이는 나중에 보게 되겠지만 실제로는 좋은 소식입니다. .
나중에 볼 수 있듯이 인수.callee가 f 식별자와 동일한 개체를 참조한다는 것을 알 수 있습니다. 이는 좋은 소식입니다.
JScript 결함을 살펴보면 무엇인지 명확해집니다. 첫째, 누출되는 식별자를 알아야 합니다(인클로징 범위를 오염시키지 않도록). 둘째, 함수 이름으로 사용되는 식별자를 절대 참조해서는 안 됩니다. 이전의 식별자는 g입니다. g의 존재를 잊어버렸다면 얼마나 많은 모호함을 피할 수 있었는지 주목하십시오. 여기서는 항상 f 또는args.callee를 통해 함수를 참조하는 것이 핵심입니다. 그리고 마지막으로 NFE 선언 중에 잘못 생성된 외부 함수를 항상 정리하는 것이 보너스 포인트입니다.
이제 JScript의 단점을 확인했으므로 피해야 할 사항이 매우 분명해졌습니다. 먼저, 식별자 유출을 인지해야 합니다(주변 범위를 오염시키지 않도록). 둘째, 식별자를 함수 이름으로 인용해서는 안 됩니다. g는 이전 예에서 볼 수 있듯이 문제가 있는 식별자입니다. g의 존재를 잊어버리면 많은 모호성을 피할 수 있습니다. 일반적으로 가장 중요한 것은 f 또는 인수.callee를 통해 함수를 참조하는 것입니다. 명명된 표현식을 사용하는 경우 이름은 디버깅 목적으로만 존재한다는 점을 기억하세요. 마지막으로 추가 포인트는 잘못 선언된 명명된 함수 표현식으로 생성된 추가 함수를 항상 정리하는 것입니다
마지막 포인트에 약간의 설명이 필요한 것 같습니다.
마지막 포인트에 약간의 설명이 필요한 것 같습니다. 설명: 추가 설명
JScript 메모리 관리
JScript 불일치에 익숙해졌으므로 이제 이러한 버그가 있는 구성을 사용할 때 메모리 소비와 관련된 잠재적인 문제를 볼 수 있습니다.
JScript와 사양의 차이점을 잘 이해하면 이러한 문제가 있는 구성을 사용할 때 메모리 소비와 관련된 잠재적인 문제를 볼 수 있습니다.
var f = (function(){
if (true) {
return function g(){};
}
return function g(){};
})()
우리는 이 익명 호출 내에서 반환된 함수를 알고 있습니다. - g 식별자를 갖는 것은 - 외부 f에 할당됩니다. 우리는 또한 명명된 함수 표현식이 불필요한 함수 개체를 생성하고 이 개체가 반환된 함수와 동일하지 않다는 것을 알고 있습니다. 여기서 메모리 문제는 이 외부 g 함수로 인해 발생합니다. 이는 반환 함수의 클로저에 문자 그대로 "갇히게" 됩니다. 이는 내부 함수가 성가신 g 함수와 동일한 범위에서 선언되기 때문에 발생합니다. g 함수에 대한 참조를 명시적으로 중단하지 않으면 메모리가 계속 소모됩니다. 익명 호출에서 반환된 함수, 즉 식별자가 g인 함수가 외부 f에 복사되는 것을 확인합니다. 또한 명명된 함수 표현식이 추가 함수 개체를 생성하고 이 개체는 반환된 개체와 동일한 함수가 아니라는 것도 알고 있습니다. 여기서 메모리 문제는 함수를 반환하는 클로저에 말 그대로 캡처된 쓸모 없는 g 함수로 인해 발생합니다. 내부 함수가 g 함수와 동일한 범위에서 선언되었기 때문입니다. g 함수에 대한 참조를 명시적으로 삭제하지 않는 한, g 함수는 항상 메모리를 차지합니다.
var f = (function(){
var f, g;
if (true) {
f = function g(){};
}
else {
f = function g(){};
}
//관련되지 않은 함수에서 더 이상 참조되지 않도록 g에 null을 할당합니다. 더 이상 외부 함수를 참조하지 않습니다.
g = null;
return f;
})()
g도 명시적으로 선언합니다. g = null 할당은 클라이언트(예: JScript가 아닌 클라이언트)에서 전역 g 변수를 생성하지 않습니다. g에 대한 참조를 null로 설정하면 가비지 수집기가 g가 참조하는 암시적으로 생성된 함수 개체를 지울 수 있습니다.
g를 명시적으로 선언했기 때문에 g=null 할당은 호환 클라이언트(예: JScirpt 엔진이 아닌 엔진)에 대한 전역 변수를 생성하지 않습니다. g에 null 참조를 제공함으로써 가비지 수집을 통해 g가 참조하는 암시적으로 생성된 함수 개체를 정리할 수 있습니다.
JScript NFE 메모리 누수를 처리할 때 nulling g가 실제로 메모리를 확보하는지 확인하기 위해 간단한 일련의 테스트를 실행하기로 결정했습니다. 문제가 밝혀졌을 때, 나는 일련의 간단한 테스트를 실행하기로 결정했습니다. g 함수에 null 참조를 제공하면 실제로 메모리가 해제되는지 확인합니다.
테스트
테스트는 간단했습니다. 명명된 함수 표현식을 통해 10000개의 함수를 생성하고 이를 배열에 저장하면 됩니다. 잠시 후 메모리 소비가 얼마나 높은지 확인한 후 참조를 무효화하고 절차를 다시 반복했습니다.
이 테스트는 매우 간단합니다. 그는 명명된 함수 표현식에서 1000개의 함수를 만들고 이를 배열에 저장합니다. 1분 정도 기다렸다가 메모리 사용량이 얼마나 높은지 확인합니다. null 참조만 추가하고 위 프로세스를 반복합니다. 다음은 제가 사용하는 간단한 테스트 사례입니다.
function createFn(){
return (function(){
var f;
if (true) {
f = function F (){
'표준' 반환;
}
}
else if (false) {
f = function F(){
'대체' 반환
}
}
else {
f = function F(){
return 'fallback';
}
}
// var F = null
return f; ;
})();
}
var arr = [ ]
for (var i=0; i<10000; i ) {
arr[i] = createFn();
}
Windows XP SP2의 Process Explorer에 표시된 결과는 다음과 같습니다.
결과는 Windows XP SP2에서 수행되었으며 Process Explorer를 통해 얻은 것입니다
IE6:
`null` 없음: 7.6K -> 20.3K
`null` 포함: 7.6K -> 18K
IE7:
없음 `null`: 14K -> 29.7K
`null` 사용: 14K -> 27K
결과는 내 가정을 어느 정도 확인했습니다. 불필요한 참조를 명시적으로 null로 설정하면 메모리가 확보되었지만 소비량의 차이는 다음과 같습니다. 10000개의 함수 개체의 경우 최대 3MB의 차이가 있습니다. 이는 대규모 애플리케이션, 장시간 동안 실행되는 애플리케이션 또는 메모리가 제한된 장치(예: 모바일 장치) 작은 스크립트의 경우 차이는 중요하지 않을 수 있습니다.
결과는 쓸모 없는 참조에 null 값을 제공하면 메모리가 확보된다는 것을 보여주는 내 가설을 어느 정도 확인합니다. 내부 차원의 소비는 그다지 크지 않은 것 같습니다. 1000개의 함수 개체에 대해 약 3M의 차이가 있어야 합니다. 그러나 대규모 애플리케이션을 설계할 때 애플리케이션은 오랜 시간 동안 실행되거나 메모리가 제한된 장치(예: 모바일 장치)에서 실행된다는 점은 분명합니다. 작은 스크립트의 경우 차이가 그다지 중요하지 않을 수 있습니다.
드디어 모든 것이 끝났다고 생각할 수도 있지만 아직은 다 끝난 것이 아닙니다 :) 제가 언급하고 싶은 아주 작은 세부 사항이 있는데 그 세부 사항은 Safari 2.x
끝이라고 생각하실 수도 있지만 아직 끝은 아닙니다. 또한 Safari의 이전 버전, 즉 Safari 2.x 시리즈에 있는 몇 가지 사소한 세부 사항에 대해서도 논의할 것입니다. Safari 2.x가 NFE를 전혀 지원하지 않는다는 주장이 웹에서 본 적이 있습니다. 사실이 아닙니다. Safari는 이를 지원하지만 구현 시 곧 보게 될 버그가 있습니다.
Safari 초기 버전에서는 사람들이 발견하지 못했지만, 즉 명명된 함수 표현식의 버그입니다. 사파리 2.x 버전에서. 하지만 웹에서 Safari 2.x가 명명된 함수 표현식을 전혀 지원하지 않는다는 주장을 본 적이 있습니다. 이것은 사실이 아닙니다. Safari는 명명된 함수 표현식을 지원하지만 나중에 볼 수 있듯이 구현에 버그가 있습니다
특정 컨텍스트에서 함수 표현식을 만나면 Safari 2.x는 프로그램을 완전히 구문 분석하지 못합니다. 모든 오류(예: SyntaxError 오류) 간단히 해결됩니다.
Safari 2.x는 특정 실행 환경에서 함수 표현식이 발견되면 전체 프로그램을 해석하지 못합니다. 오류(예: SyntaxError)가 발생하지 않습니다. 다음과 같이 표시됩니다.
(function f(){})(); // <== 유명한 함수 표현식 NFE
alert(1); //앞의 표현식은 전체 프로그램이 실패했기 때문에, 이전 표현식이 전체 프로그램에서 실패하기 때문에 이 줄에 도달하지 못했습니다.
다양한 테스트 사례를 살펴본 후 Safari 2.x가 할당 표현식의 일부가 아닌 경우 명명된 함수 표현식을 구문 분석하지 못한다는 결론에 도달했습니다. . 할당 표현식의 몇 가지 예는 다음과 같습니다.
일부 테스트 사례를 테스트한 후 Safari는 할당 표현식의 일부가 아닌 경우 명명된 함수 표현식을 해석한다는 결론을 내렸습니다.할당 표현식의 몇 가지 예는 다음과 같습니다
// 변수 선언의 일부
var f = 1
//단순 할당의 일부
f = 2 , g = 3 ;
// return 문의 일부
(function(){
return (f = 2);
})()
이것은 이름을 넣는 것을 의미합니다. 함수 표현식을 할당에 추가하면 Safari가 "행복"해집니다.
이는 명명된 함수 표현식을 할당에 넣으면 Safari가 "행복"해진다는 의미입니다.
(function f(){}) // 실패합니다.
var f = function f(){}; // 성공적으로 작동합니다
(function(){
return function f(){}; // 실패합니다
}) ();
(function(){
return (f = function f(){}); // 성공적으로 작동합니다
})()
setTimeout(function f(){ }, 100); // 실패
또한 할당 없이 명명된 함수 표현식을 반환하는 것과 같은 일반적인 패턴을 사용할 수 없다는 의미입니다.
이것은 또한 할당 표현식 없이 이 일반 패턴을 반환 명명된 함수 표현식으로 사용할 수 없습니다.
//이 Safari2와 호환되지 않는 구문 대신:
(function() {
if (featureTest) {
return function f(){};
}
return function f(){}
})(); / 좀 더 장황한 대안을 사용해야 합니다:
(function( ){
var f;
if (featureTest) {
f = function f(){};
}
else {
f = function f(){};
}
return f;
})()
// 또는 다른 변형:
(function(){
var f;
if (featureTest) {
return (f = 함수 f(){});
}
return (f = 함수 f(){ });
})();
/*
안타깝게도
반환 함수의 클로저에 갇히게 되는 함수에 대한 추가 참조를 도입합니다. 추가 메모리 사용을 방지하기 위해
모든 명명된 함수 표현식을 하나의 단일 변수에 할당할 수 있습니다.
불행히도 이렇게 하면 함수에 대한 또 다른 참조가 도입됩니다.
반환 함수의 클로저에 포함됩니다.
과도한 메모리 사용을 방지하기 위해 명명된 모든 함수 표현식을 별도의 변수
var __temp
(function(){
if (featureTest) {
return (__temp = function f(){});
}
return (__temp = function f(){})
; ..
(function(){
if (featureTest2) {
return (__temp = function g(){});
}
return (__temp = function g( ){ });
})();
/*
이전 참조를 삭제하여
과도한 메모리 사용을 방지합니다. >*/
Safari 2.x 호환성이 중요한 경우 "호환되지 않는" 구문이 소스에 나타나지 않도록 해야 합니다. 물론 이는 상당히 짜증나는 일이지만 특히 달성이 가능합니다. 문제의 근본 원인을 알 때
Safari2.x 호환성이 매우 중요하다면. 호환되지 않는 구조가 더 이상 코드에 나타나지 않도록 해야 합니다. 물론 이는 매우 짜증나는 일이지만, 특히 문제의 원인을 알고 있는 경우에는 확실히 가능합니다.
var f = function g(){}; 🎜>
// 함수 표현에 `g` 식별자가 부족하다는 점에 주목하세요.
String(g); // function () { }
이미 그랬듯이 이것은 실제로 큰 문제는 아닙니다. 앞서 언급한 함수 디컴파일은 어차피 의존해서는 안되는 부분입니다.
이건 큰 문제는 아닙니다. 앞서 말했듯이 함수 디컴파일은 어떤 경우에도 신뢰할 수 없습니다.
해결책
var fn = (function(){
//
var f에 함수 객체를 할당하는 변수 선언;
// 조건부 생성 명명된 함수
// f에 참조를 할당하고 `f`에 참조를 할당
if (true) {
f = function F(){ }
}
else if (false) {
f = 함수 F(){ }
}
else {
f = 함수 F (){ }
}
//`null 지정 ` 함수 이름에 해당하는 변수에
//이것은 함수 개체를 만들 수 있습니다( 이는 해당 식별자로 참조되는 함수 개체를 표시합니다.
// 가비지 수집에 사용 가능
var F = null;
//return 조건에 따라 정의된 함수 반환
return f;
})()
마지막으로 이를 적용하는 방법은 다음과 같습니다. 실제 생활에서 크로스 브라우저 addEvent 함수와 같은 것을 작성할 때:
마지막으로 크로스 브라우저 addEvent 함수와 유사한 유사한 함수가 있지만 다음은 이 기술을 응용 프로그램에서 사용할 수 있는 방법입니다. 실제 애플리케이션
// 1) 별도의 범위로 선언을 묶습니다.
var addEvent = (function(){
var docEl = document.documentElement;
/ / 2)
var fn;
if (docEl.addEventListener) {
//에 함수를 할당할 변수를 선언합니다. 3) 함수에 a를 반드시 지정하세요. 설명 식별자
fn = function addEvent(element, eventName, callback) {
element.addEventListener(eventName, callback, false)
}
}
else if (docEl.attachEvent) {
fn = function addEvent(element, eventName, callback) {
element.attachEvent('on' eventName, callback)
}
}
else {
fn = function addEvent; (element, eventName, callback) {
element['on' eventName] = callback;
}
}
// 4 ) JScript에서 생성된 `addEvent` 함수 정리
// 할당 앞에 `var`을 추가하세요.
// 함수 상단에 addEvent를 선언하거나 함수 상단에 `addEvent`를 선언하세요.
var addEvent = null
// 5) 마지막으로 `fn`에 의해 참조되는 반환 함수
return fn;
})()
대체 솔루션
실제로 대체 방법이 존재한다는 점을 언급할 가치가 있습니다.
호출 스택에 설명이 포함된 이름을 사용합니다.
우선 표현식 대신 선언을 통해 함수를 정의하는 것이
가능한 경우가 많습니다.
하나 이상의 함수를 생성할 필요가 없는 경우에만 실행 가능합니다.
실제로는 호출 스택에 설명 이름(함수 이름)을 표시하는 대체 방법일 뿐이라는 점에 유의해야 합니다. . 명명된 함수 표현식을 사용할 필요가 없는 메서드입니다. 첫째, 표현식을 사용하는
대신 선언을 사용하여 함수를 정의하는 것이 가능한 경우가 많습니다. 이 옵션은 일반적으로 여러 함수를 생성할 필요가 없는 경우에만 적합합니다.
var hasClassName = (function(){
// 일부 개인 변수 정의 일부 개인 변수 정의
var 캐시 = { };
//함수 정의 사용 함수 선언 사용
function hasClassName(element, className) {
var _className = '(?:^|\s )' className '(?:\s |$)'
var re = 캐시[ _className] || (cache[_className] = new RegExp(_className));
return re.test(element.className)
}
// return 함수 return function hasClassName;
})();
함수 정의를 분기할 때는 분명히 작동하지 않습니다.
그럼에도 불구하고
Tobie Langel이 처음으로 사용한 흥미로운 패턴이 있습니다. . 작동 방식은
함수 선언을 사용하여 모든 함수를 미리 정의하지만 약간 다른
식별자를 제공하는 것입니다:
이 방법은 분명히 다중 방향 함수 정의에는 적용되지 않습니다. 그런데 토비가
랭겔이 사용하는 걸 처음 봤던 재미있는 방법이 있다. 이는 함수 선언으로 모든 함수를 정의하지만 함수 선언에 약간 다른 식별자를 제공합니다.
var addEvent = (function(){
var docEl = document.documentElement;
function addEventListener(){
/* ... */
}
function attachmentEvent(){
/* ... */
}
function addEventAsProperty(){
/* ... */
}
if (typeof docEl.addEventListener != 'undefine') {
return addEventListener;
}
elseif (typeof docEl.attachEvent != 'undefine') {
return attachmentEvent; }
return addEventAsProperty
})();
멋진 접근 방식이지만 단점도 있습니다. 첫째,
다른 식별자를 사용하면 명명 일관성이 손상됩니다.
좋은지 나쁜지 명확하지 않습니다. 어떤 사람들은 동일한
이름을 선호하는 반면, 다른 사람들은 다양한 이름을 선호할 수도 있습니다. 결국, 서로 다른
이름이 사용된 구현에 대해 "말"할 수 있는 경우가 많습니다. 예를 들어, 디버거에서
“attachEvent”를 보면 addEvent의 attachmentEvent 기반 구현임을 알 수 있습니다. 반면
구현 관련 이름은 전혀 의미가 없을 수도 있습니다.
이러한 방식으로 API를 제공하고 "내부" 함수에 이름을 지정하는 경우 API 사용자는
이러한 모든 구현 세부 사항에서 쉽게 길을 잃을 수 있습니다.
이 방법은 일반적으로 사용되지 않으며 일반적으로 사용되지 않습니다.是件好的事情还是件坏的事情还不好说。
유명한 이름이 없으며 일반적으로 이름이 같지 않습니다. AttachEvent”,你就可以
알고 있는 addEvent基于attentEvent는 一个实现입니다. 🎜>内부적 函数, api적용자可能会被这些实现细节搞糊涂。
이 문제에 대한 해결책은 다른 이름 지정
규칙을 사용하는 것일 수 있습니다. 너무 자세한 내용을 소개하지 않도록 주의하세요.
생각나는 대안은 다음과 같습니다.
이 방법은 다음과 같습니다. 당신의 이름을 정하는 법
`addEvent`, `altAddEvent` 및 `fallbackAddEvent`
// 또는
`addEvent`, `addEvent2`, `addEvent3`
// 또는
`addEvent_addEventListener`, ` addEvent_attachEvent`, `addEvent_asProperty`
이 패턴의 또 다른 사소한 문제는
메모리 소비 증가입니다. 모든 함수 변형을 미리 정의하면
사용되지 않는 N-1 함수를 암시적으로 생성할 수 있습니다. 보시다시피, document.documentElement에서 attachmentEvent가 발견되면
addEventListener나 addEventAsProperty가 실제로 사용되지 않습니다. 하지만
이미 메모리를 소비하고 있습니다.
JScript의 버그가 있는 명명된 표현식과 같은 이유로 할당이 취소되지 않는 메모리 - 두 함수 모두
반환하는 클로저에 "갇혀" 있습니다.
N-1个은 일반적으로 모든 상면에 사용할 수 있는 인터페이스를 제공합니다.函数。你可以发现,如果attachEvent
에서 document.documentElement중앙에는 addEventListener와 addEventAsProperty가 있습니다.
사용 가능.Jscript에는 버그가 있습니다. 거기에는 같은 것이 있습니다.个函数被'trapped'在闭
包中。
이런 소비 증가는 물론 문제가 되지 않습니다. Prototype.js와 같은
라이브러리가 이 패턴을 사용한다면
추가 함수 객체가 100-200개 이하로 생성될 것입니다. 함수가 이러한 방식으로
반복적으로(런타임 시) 생성되지 않고 단 한 번(로드 시
만) 생성된다면 걱정할 필요가 없습니다.
이는 매우 강력한 응용 프로그램입니다.个多于的函数对象被创
建。如果函数没有被重复地(运行时)用这种方式创建,只是在加载时被创建一次,你可能就不用担心这个问题。