서문
인터넷에서 명명된 함수 표현에 대해 깊이 있는 논의를 반복한 사람을 본 적이 없습니다. 이로 인해 인터넷에서 다양한 오해가 나타났습니다. 이 기사에서는 JavaScript의 명명 기능을 원리와 실제 측면에서 논의합니다. 측면. 표현의 장점과 단점.
간단히 말하면, 디버그 또는 프로파일러 분석 중에 함수 이름을 설명하기 위한 명명된 함수 표현식의 사용자는 단 한 명뿐입니다. 함수 이름을 사용하여 재귀를 구현할 수도 있지만 곧 알게 될 것입니다. 실제로는 비현실적입니다. 물론 디버깅에 관심이 없다면 걱정할 필요가 없습니다. 그렇지 않고 호환성에 대해 알고 싶다면 계속 읽어야 합니다.
먼저 함수 표현식이 무엇인지 살펴보고 최신 디버거가 이러한 표현식을 처리하는 방법에 대해 이야기해 보겠습니다. 이미 이에 익숙하다면 이 섹션을 건너뛰시기 바랍니다.
함수 표현식 및 함수 선언
ECMAScript에서 함수를 생성하는 가장 일반적인 두 가지 방법은 함수 표현식과 함수 선언입니다. ECMA 사양에서는 함수라는 한 가지 사항만 명확히 하기 때문에 둘 사이의 차이점은 약간 혼란스럽습니다. 선언에는 식별자(식별자) (모든 사람이 종종 함수 이름이라고 부르는 것)가 있어야 하며, 함수 표현식에서는 이 식별자를 생략할 수 있습니다.
함수 선언:
함수 함수 이름(매개변수: 선택 사항) { 함수 body}
함수 표현식:
함수 함수명(선택) (매개변수: 선택) { 함수 본문}
그래서 함수 이름이 선언되지 않은 경우 표현식이어야 함을 알 수 있으며, 하지만 함수 이름이 선언되면 그것이 함수 선언인지 함수 표현식인지 어떻게 판단할 수 있을까요? ECMAScript는 문맥에 따라 구별됩니다. function foo(){}가 할당 표현식의 일부인 경우 이는 함수 표현식입니다. function foo(){}가 함수 본문 내에 포함되거나 프로그램 맨 위에 있는 경우입니다. 함수 선언.
function foo(){} // 선언 , 이는 프로그램의 일부이기 때문입니다.
var bar = function foo(){}; // 표현식의 일부이기 때문에
new function bar(){}; is new Expression
(function(){
function bar(){} // 선언, 왜냐하면 함수 본문의 일부이기 때문입니다
})()
있음 또 다른 함수 표현식은 덜 일반적이며 괄호(function foo(){})로 묶입니다. 괄호()는 그룹화 연산자이고 내부에만 표현식을 포함할 수 있기 때문입니다. 몇 가지 예:
function foo(){} / / 함수 선언
(function foo(){}); // 함수 표현식: 그룹화 연산자에 포함됨
try {
(var x = 5) // 그룹화 연산자, 표현식만 포함함 not 문: var here is the 문
} catch(err) {
// SyntaxError
}
생각하시면 됩니다. eval을 사용하면 JSON이 실행될 때, JSON 문자열은 일반적으로 괄호(eval('(' json ')'))로 묶입니다. 그 이유는 그룹화 연산자, 즉 이 괄호 쌍이 파서가 JSON의 중괄호를 표현식으로 구문 분석하도록 하기 때문입니다. 코드 블록 대신.
try {
{ "x" : 5 } ; // "{" 및 "}"는 코드 블록으로 구문 분석됩니다.
} catch(err) {
// SyntaxError
}
({ "x": 5 }); // 그룹화 연산자는 "{" 및 "}"를 객체 리터럴로 구문 분석하도록 강제합니다.
식과 선언 사이에는 매우 미묘한 차이가 있습니다. 첫째, 함수 선언은 다른 항목보다 먼저 구문 분석되고 평가됩니다. 값이 먼저 구문 분석되고 평가됩니다. 선언이 코드의 마지막 줄에 있더라도 동일한 범위의 첫 번째 표현식보다 먼저 구문 분석/평가됩니다. 다음 예제를 참조하세요. . 그러나 경고가 실행되면 fn이 이미 정의되어 있습니다.
alert(fn());
function fn() {
return 'Hello world!''
}
추가로 한 가지가 더 있습니다. 주의할 점, function 선언은 조건문 내에서 사용할 수 있지만 표준화되어 있지 않아 환경에 따라 실행 결과가 다를 수 있으므로 이 경우 함수 표현식을 사용하는 것이 가장 좋습니다.
// 이러지 마세요!
// 일부 브라우저는 첫 번째 함수를 반환하고 일부 브라우저는 두 번째 함수를 반환하기 때문에
if (true) {
function foo() {
return 'first';
}
else {
function foo() {
return 'second';
}
}
foo()
// 반대로 이 경우에는 함수 표현식
var foo;
if (true) {
foo = function() {
return 'first'
};
else {
foo = function() {
return '두 번째';
}
foo()
함수 선언의 경우 다음과 같습니다.
함수 선언은 프로그램이나 함수 본문 내에서만 나타날 수 있습니다. 구문상 블록({ ... }) 내부(예: if, while 또는 for 문 내)에 나타날 수 없습니다. 블록은 명령문만 포함할 수 있고 함수 선언과 같은 소스 요소는 포함할 수 없기 때문입니다. 반면, 규칙을 자세히 살펴보면 표현식이 블록에 나타날 수 있는 유일한 방법은 표현식 문의 일부인 경우라는 것을 알 수 있습니다. 그러나 사양에는 표현식 문이 키워드 function으로 시작할 수 없다고 명시되어 있습니다. 이것이 실제로 의미하는 바는 함수 표현식이 명령문이나 블록에 나타날 수 없다는 것입니다(블록은 명령문으로 구성되기 때문입니다).
함수문
ECMAScript의 구문 확장 중 하나가 함수문입니다. 현재는 Gecko 기반의 브라우저에서만 이 확장을 구현하고 있으므로, 다음 예시에서는 학습용으로만 사용하고 있는 것 같습니다. 일반적으로 권장되지 않습니다(Gecko 브라우저용으로 개발하는 경우 제외).
1. 일반문을 사용할 수 있는 경우 블록 블록을 포함하여 함수문도 사용할 수 있습니다.
else {
function f(){ }
}
2. 조건부 실행을 포함하여 다른 명령문과 마찬가지로 함수 명령문을 구문 분석할 수 있습니다.
else {
function foo(){ return 2 ; }
}
foo(); // 1
// 참고: 다른 클라이언트는 foo를 함수 선언으로 구문 분석합니다.
// 따라서 두 번째 foo는 첫 번째 foo를 덮어씁니다. 결과는 1 대신 2를 반환합니다
3. 함수 명령문은 변수 초기화 중에 선언되지 않지만 런타임 시 함수 표현식과 동일합니다. 그러나 함수 문의 식별자가 선언되면 함수 전체 범위에 적용됩니다. 식별자 유효성은 함수 문을 함수 표현식과 다르게 만드는 것입니다(다음 섹션에서 명명된 함수 표현식의 구체적인 동작을 보여줍니다).
// 여기에 입력하면 foo가 전체 범위에 선언됩니다.
function foo(){ return 1; 🎜>}
else {
// 여기에 오지 않으므로 foo는 선언되지 않습니다.
function foo(){ return 2 }
}
typeof foo; "
그러나 다음 표준 호환 코드를 사용하여 위 예의 함수 명령문을 모델링할 수 있습니다.
코드 복사
foo = function foo() { return 2 };
4. 함수 명령문 및 함수 선언용 문자 식별자를 포함하여 문자열 표현은 유사합니다.
코드 복사
// 함수 선언
function foo(){ return 1; }
if (true) {
//
function foo(){ return 2를 함수 문으로 다시 작성 ; }
}
foo(); // FF3 이하는 1, FF3.5 이상은 2를 반환합니다.
// 단, 함수 표현식이 앞에 오면 쓸모가 없습니다
var foo = function(){ return 1; };
if (true) {
function foo(){ return 2; }
}
foo(); 🎜>
이름이 지정된 함수 표현식
함수 표현식은 실제 응용 프로그램에서 여전히 매우 일반적입니다. 웹 개발의 일반적인 패턴은 성능 최적화를 달성하기 위해 특정 특성 테스트를 기반으로 함수 정의를 위장하는 것입니다. 범위에서는 기본적으로 함수 표현식을 사용해야 합니다.
var contain = (function() {
var docEl = document.documentElement;
if (typeof docEl. CompareDocumentPosition != '정의되지 않음') {
return function(el, b) {
return (el.compareDocumentPosition(b) & 16) !== 0
}
else if (typeof docEl.contains != 'undefine') {
return function(el, b) {
return el !== b && el .contains(b)
}; }
return function(el, b) {
if (el === b) return false
while (el != b && (b = b.parentNode) != null); >return el === b;
})();
언급된 함수 표현식 물론 이전 예제에는 이름이 있어야 합니다. foo(){};는 유효한 명명된 함수 표현식이지만 기억해야 할 것이 하나 있습니다. 이 이름은 새로 정의된 함수의 범위 내에서만 유효합니다. 왜냐하면 사양에서는 식별자가 외부 범위에서 유효할 수 없다고 규정하고 있기 때문입니다. 🎜>
이것이 요구사항인데 명명된 함수 표현식은 어떻게 사용하나요? 이름이 왜요?
처음에 말했듯이, 이름을 지정하면 디버깅 프로세스가 더 편리해질 수 있습니다. 왜냐하면 디버깅할 때 호출 스택의 각 항목에 이를 설명하는 고유한 이름이 있으면 디버깅 프로세스가 훌륭해지기 때문입니다. , 느낌이 다릅니다.
디버거의 함수 이름
함수에 이름이 있으면 디버거는 디버깅 중에 호출 스택에 해당 이름을 표시합니다. 일부 디버거(Firebug)는 함수를 사용하는 것과 동일한 역할을 갖도록 함수에 이름을 지정하고 표시하는 경우가 있지만 일반적으로 이러한 디버거는 이름 지정에 대한 간단한 규칙만 설치하므로 가격이 크지 않다고 말하면 다음을 살펴보겠습니다. 예:
코드 복사
코드는 다음과 같습니다.
foo();
// 여기서는 이름이 있는 3개의 함수 선언을 사용합니다
// 따라서 디버거가 디버거 문으로 이동하면 Firebug 호출 스택은 매우 명확해 보입니다.
// 이름이 명확하기 때문에 표시되는
baz
bar
foo
expr_test.html()
콜 스택 정보를 보면 foo가 bar를 호출하고 bar가 baz를 호출한다는 것을 확실히 알 수 있습니다. (그리고 foo 자체는 expr_test.html 문서의 전역 범위에서 호출됩니다.) 그러나 또 다른 멋진 곳이 있습니다. 즉, 방금 언급한 Firebug는 익명 표현식 이름 지정 기능입니다:
코드 복사
baz
bar() //보이죠?
foo
expr_test.html()
그럼 함수 표현식이 조금 더 복잡해지면 디버거가 그다지 똑똑하지 않고 호출 스택에서만 볼 수 있습니다. 표시:
코드 복사
코드는 다음과 같습니다.
function foo(){
return bar();
}
var bar = (function(){
if (window.addEventListener) {
return function( ){
return baz();
};
}
else if (window.attachEvent) {
return function() {
return baz(); ;
}
})();
function baz(){
디버거;
}
foo()// 호출 스택
baz
(?)() // 물음표 입니다
foo
expr_test.html()
또한, 여러 변수에 함수를 할당할 경우 명령어도 나옵니다. 우울한 질문:
}
var bar = function(){
debugger;
}
var baz = bar; > Alert('spoofed');
};
foo();
// 호출 스택:
bar()
foo
expr_test.html()
🎜 >
이때 호출 스택에는 foo가 bar를 호출한 것으로 표시되지만 실제로는 그렇지 않습니다. 이 문제의 원인은 baz와 Alert('spoofed')가 포함된 다른 함수가 참조 교환을 했기 때문입니다. 발생했습니다.
최종 분석에서 가장 위임된 방법은 함수 표현식에 이름을 부여하는 것, 즉 명명된 함수 표현식을 사용하는 것입니다. 명명된 표현식을 사용하여 위의 예를 다시 작성해 보겠습니다(즉시 호출되는 표현식 블록에서 반환되는 두 함수의 이름은 막대입니다).
코드 복사
return function bar(){
return baz();
}
else if (window.attachEvent) {
return 함수 bar() {
return baz();
};
}
})()
function baz(){
디버거; ()
// 명확한 호출 스택 정보를 다시 볼 수 있습니다!
baz
bar
foo
expr_test.html()
좋아요. 또 다른 비결을 배웠나요? 하지만 너무 흥분하기 전에 특이한 JScript를 살펴보겠습니다.
JScript의 버그
더 나쁜 것은 IE의 JScript ECMAScript 구현이 명명된 함수 표현식을 심각하게 혼동하여 많은 사람들이 명명된 함수 표현식에 반대하게 만든다는 것입니다. 심지어 최신 버전(IE8) 버전 5.8을 사용하더라도 여전히 다음과 같은 문제가 있습니다. 문제.
IEE가 구현 과정에서 어떤 실수를 했는지 살펴보겠습니다. 속담처럼 적을 알아야만 무적이 될 수 있습니다. 다음 예를 살펴보겠습니다.
예제 1: 함수 표현식의 식별자가 외부 범위로 유출됩니다
코드 복사
코드는 다음과 같습니다.
코드 복사
코드는 다음과 같습니다. 다음:
코드는 다음과 같습니다.
예 4: 함수 선언만 순차적으로 구문 분석하고 조건문 블록을 무시합니다.
코드는 다음과 같습니다.
var f = function g() {
return 1;
}
if (false) {
f = function g(){
return 2; 🎜>};
}
g(); // 2
arguments.callee와 다른 개체를 비교할 때 차이점이 무엇인지 궁금할 것입니다.
return [
args.callee == f,
arguments.callee == g
}
f(); // [참, 거짓]
g(); false, true]
보시다시피,args.callee의 참조는 항상 호출되는 함수입니다. 사실 이것도 좋은 일인데, 이에 대해서는 나중에 설명하겠습니다. 흥미로운 예는 선언이 포함되지 않은 대입문에서 명명된 함수 표현식을 사용하는 것입니다.
다음 코드를 따르세요. 분석에서 우리는 원래 전역 속성 f를 만들고 싶었습니다(이름이 지정된 life를 사용하는 일반 익명 함수와 혼동하지 않도록 주의하세요). 먼저 JScript는 표현식을 함수 선언으로 구문 분석했습니다. 왼쪽의 f는 지역변수로 선언(일반 익명함수에서의 선언과 동일)한 뒤, 함수가 실행되면 이미 f가 정의되어 있고, 오른쪽의 f(){} 함수가 직접적으로 값은 지역 변수 f에 할당되므로 f는 전역 속성이 아닙니다.
JScript의 메모리 관리
이러한 비호환 코드 구문 분석 버그를 알고 나면 실제로 문제가 있음을 알 수 있습니다. 예를 들어 보겠습니다.
코드 복사
return function g(){};
})();
우리는 이 익명 함수가 반환된 함수(식별자가 g인 함수)를 호출한 다음 이를 외부 f에 할당한다는 것을 알고 있습니다. 또한 명명된 함수 표현식이 반환된 함수 개체와 동일하지 않은 중복 함수 개체로 이어진다는 것도 알고 있습니다. 그래서 이 중복된 g 함수는 반환 함수가 닫힐 때 죽어서 메모리 문제가 발생했습니다. 이는 if 문 내부의 함수가 g와 동일한 범위에서 선언되었기 때문입니다. 이 경우 g 함수에 대한 참조를 명시적으로 연결 해제하지 않으면 항상 메모리를 차지하게 됩니다.
코드 복사
}
else {
f = 함수 g(){}; >}
// g를 null로 설정하면 더 이상 메모리를 차지하지 않습니다.
g = null
return f;
g를 null로 설정하면 가비지 수집기가 g에서 참조하는 암시적 함수를 회수합니다. 코드를 확인하기 위해 몇 가지 테스트를 수행하여 메모리가 회수되는지 확인합니다.
테스트
테스트는 매우 간단합니다. 명명된 함수 표현식으로 10,000개의 함수를 만든 다음 배열에 저장하면 됩니다. 잠시 기다렸다가 이러한 기능이 차지하는 메모리 양을 확인하십시오. 그런 다음 해당 참조의 연결을 끊고 프로세스를 반복하십시오. 테스트 코드는 다음과 같습니다.
function createFn (){
return (function(){
var f;
if (true) {
f = function F(){
return 'standard';
};
}
else if (false) {
f = 함수 F(){
'대체' 반환
}
else {
f = 함수 F(){
'대체' 반환
}
// var F = null
return f; 🎜>var arr = [ ];
for (var i=0; iarr[i] = createFn()
}
Windows XP에서 실행하면 SP2의 작업 관리자에서 다음 결과를 볼 수 있습니다.
코드 복사
`null`: 14K -> 27K
예상대로 디스플레이 연결 끊김으로 인해 메모리가 해제될 수 있지만 해제되는 메모리는 많지 않습니다. , 10,000개의 함수 개체는 3M에서만 출시됩니다. 이는 일부 작은 스크립트에는 별거 아니지만 대규모 프로그램이나 메모리가 부족한 장치에서 오랫동안 실행하는 경우 매우 필요합니다.
Safari 2.x의 JS 파싱에도 버그가 있는데, 버전이 상대적으로 낮기 때문에 여기서는 소개하지 않겠습니다. 보고 싶으신 분들은 영문 정보를 잘 확인해주세요. .
SpiderMonkey의 단점
여기서 매우 흥미로운 점 중 하나는 ECMA-262가 이 "특수" 객체(함수 식별자를 보유함)를 정의하는 방식입니다. 표준에서는 "새 Object() 표현식을 호출하는 것처럼" 이 객체를 생성한다고 말합니다. 이 문장을 문자 그대로 이해한다면 이 개체는 전역 개체의 인스턴스여야 합니다. 그러나 문자 그대로 이를 수행하는 구현은 단 하나 뿐이며 그 구현은 SpiderMonkey입니다. 따라서 SpiderMonkey에서 Object.prototype을 확장하면 함수의 로컬 범위를 방해할 수 있습니다.
코드 복사
x의 값은 Object.prototype.x(외부)의 값이기도 합니다. 따라서 x의 역할을 포함하는 외부 함수의 범위도 마찬가지입니다. = 'inner'). domain)은 구문 분석되지 않습니다.
*/
(function foo(){
alert(x); // 프롬프트 상자에 다음이 표시됩니다. external
})();
})()
그러나 이후 버전의 SpiderMonkey에서는 보안 취약점으로 간주되어 위의 동작을 변경했습니다. 즉, "특수" 개체는 더 이상 Object.prototype을 상속하지 않습니다. 그러나 Firefox 3 이하를 사용하는 경우 이 동작을 "다시 방문"할 수 있습니다.
내부 개체를 전역 개체 개체로 구현하는 또 다른 브라우저는 Blackberry 브라우저입니다. 현재 해당 활동 개체(활성화 개체)는 여전히 Object.prototype을 상속합니다. 그러나 ECMA-262에서는 "새 Object() 표현식을 호출하는 것과 같이"(또는 NFE 식별자를 보유하는 객체를 생성하는 것과 같이) 활성 객체를 생성해야 한다고 말하지 않습니다. 다른 사람들의 표준에서는 활동 개체가 표준의 메커니즘이라고만 말합니다.
그럼 BlackBerry에서 무슨 일이 일어나고 있는지 살펴보겠습니다.
Object.prototype.x = '외부';
(function(){
var x = 'inner';
(function(){
/*
Inside 스코프 체인에서 x를 파싱할 때 로컬 함수의 활성 객체를 먼저 검색합니다. 물론 이 객체에서는 x를 찾을 수 없습니다.
그러나 활성 객체는 Object.prototype을 상속하므로 다음 것입니다. x가 검색됩니다. 대상은 Object.prototype이고
Object.prototype에는 x의 정의가 있습니다. 결과적으로 x의 값은 이전 예와 마찬가지로
에 포함되어 있습니다. x = 'inner'. 외부 함수(활성 객체)의 범위는 확인되지 않습니다.
*/
alert(x); // 표시: 외부
})(); })();
var constructor = function(){ return 1; }; (function(){
constructor(); // 평가 결과는 1이 아닌 {}입니다(Object.prototype.constructor()를 호출하는 것과 동일).
constructor = == Object.prototype.constructor; // true
toString === Object.prototype.toString; // true
// ……
})();
이 문제를 방지하려면 Object.prototype에서 toString, valueOf, hasOwnProperty 등과 같은 속성 이름을 사용하지 마세요.
// 조건부로 명명된 함수를 생성합니다
// 해당 참조를 f에 할당합니다
if ( true) {
f = 함수 F(){ }
}
else if (false) {
f = 함수 F(){ }
}
else {
f = function F(){ }
}
// 함수명(식별자)에 해당하는 변수를 선언하고 null로 할당
// 실제로 해당 함수가 참조하는 함수입니다. 식별자 개체가
// 재활용 가능하다는 것을 알 수 있도록 표시됩니다.
var F = null
//
return f; >}) ();
마지막으로 위의 기술을 적용한 응용예를 제시하는데, 바로 크로스 브라우저 addEvent 함수 코드입니다:
코드 복사
var fn;
if (docEl.addEventListener) {
// 3) 의도적으로 함수에 설명적 식별자 제공
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가 선언되지 않은 경우
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 hasClassName
})(); 분명히 이 솔루션은 여러 분기 기능 정의가 있는 경우 작동하지 않습니다. 그러나 가능해 보이는 패턴이 있습니다. 즉, 함수 선언을 사용하여 모든 함수를 미리 정의하고 이러한 함수에 대해 서로 다른 식별자를 지정합니다.
/* .. */
}
function attachmentEvent(){
/* ... */
}
function addEventAsProperty(){
/* . .. */
}
if (typeof docEl.addEventListener != '정의되지 않음') {
return addEventListener;
}
elseif (typeof docEl.attachEvent != '정의되지 않음') {
return attachmentEvent;
}
return addEventAsProperty;
})();
이 솔루션은 훌륭하지만 단점이 없는 것은 아닙니다. 첫째, 다른 식별자 사용으로 인해 명명 일관성이 손실됩니다. 이것이 좋은지 나쁜지는 말할 것도 없고, 적어도 충분히 명확하지는 않습니다. 어떤 사람들은 같은 이름을 사용하는 것을 좋아하지만 다른 사람들은 표현의 차이에 전혀 신경 쓰지 않습니다. 그러나 결국 다른 이름은 사람들에게 사용된 다른 구현을 상기시킵니다. 예를 들어, 디버거에서 attachmentEvent를 보면 addEvent가 attachmentEvent 구현을 기반으로 한다는 것을 알 수 있습니다. 물론 구현에 따른 이름 지정이 항상 작동하는 것은 아닙니다. API를 제공하고 이런 방식으로 함수 이름을 내부로 지정한다고 가정해 보겠습니다. 그러면 API 사용자는 해당 구현의 세부 사항으로 인해 쉽게 혼란을 겪을 수 있습니다.
이 문제를 해결하려면 당연히 좀 더 합리적인 명명 방식을 생각해야 합니다. 하지만 더 이상 문제를 일으키지 않는 것이 핵심입니다. 지금 생각나는 해결책은 다음과 같습니다:
// 또는
'addEvent', 'addEvent2', 'addEvent3'
// 아니면
'addEvent_addEventListener', 'addEvent_attachEvent', 'addEvent_asProperty'
코드 복사
게다가 이 모드에도 작은 문제가 있는데, 바로 메모리 사용량이 늘어난다는 점이다. N개의 함수를 다른 이름으로 미리 만들어 놓는 것은 N-1개의 함수를 사용하지 않는다는 의미입니다. 특히 document.documentElement에 attachmentEvent가 포함되어 있으면 addEventListener 및 addEventAsProperty가 전혀 필요하지 않습니다. 그러나 이 메모리는 모두 메모리를 차지합니다. 게다가 이 메모리는 JScript의 지저분한 명명 표현식과 같은 이유로 해제되지 않습니다. 두 함수 모두 반환된 함수의 클로저에 "갇혀" 있습니다.
그러나 메모리 사용량 증가 문제는 실제로 큰 문제가 아닙니다. Prototype.js와 같은 라이브러리가 이 패턴을 채택하면 1~200개 이상의 함수만 생성됩니다. 이러한 함수가 반복적으로(런타임 시) 생성되지 않고 단 한 번(로드 시) 생성되는 한 걱정할 필요가 없습니다.
WebKit의 displayName
WebKit 팀은 이 문제에 대해 다소 대안적인 전략을 채택했습니다. 익명 및 명명된 함수는 표현력이 매우 낮기 때문에 WebKit에서는 "특수" displayName 속성(기본적으로 문자열)을 도입합니다. 개발자가 함수의 이 속성에 값을 할당하면 디버깅 중에 이 속성의 값이 사용됩니다. 프로그래머나 프로파일러의 "이름" 함수 대신. Francisco Tolmasky는 이 전략의 원칙과 구현을 자세히 설명합니다.
향후 고려 사항
ECMAScript-262(현재 초안)의 향후 버전 5에는 소위 엄격 모드가 도입될 예정입니다. 엄격 모드 구현을 활성화하면 언어를 불안정하고 신뢰할 수 없으며 안전하지 않게 만드는 언어 기능이 비활성화됩니다. 보안상의 이유로args.callee 속성은 엄격 모드에서 "차단"될 것이라고 합니다. 따라서 엄격 모드에서 Argument.callee에 액세스하면 TypeError가 발생합니다(ECMA-262 5판, 섹션 10.6 참조). 여기서 엄격 모드를 언급하는 이유는 5판 표준을 기반으로 한 구현에서 재귀 연산을 수행하기 위해 인수.callee를 사용할 수 없는 경우 명명된 함수 표현식을 사용할 가능성이 크게 높아지기 때문입니다. 이런 의미에서 명명된 함수 표현식의 의미와 버그를 이해하는 것이 훨씬 더 중요합니다.

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

드림위버 CS6
시각적 웹 개발 도구

WebStorm Mac 버전
유용한 JavaScript 개발 도구

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경
