"피트"라는 단어는 "트랩"을 의미합니다. JavaScript의 "약한 언어"의 특성으로 인해 사용 중에는 매우 느슨하고 유연하지만 "타격"도 매우 쉽습니다. 이 구덩이는 종종 숨겨져 있으므로 학습과 JS를 적용하는 길에서 매끄러운 항해를 위해 눈을 뜨게해야합니다.
1. 글로벌 변수
JavaScript는 기능을 통해 스코프를 관리합니다. 함수 내부에 선언 된 변수는이 기능 내부에만 가능하며 함수 외부에서 사용할 수 없습니다. 반면에, 글로벌 변수는 어떤 함수 외부로 선언되거나 간단하고 단순히 선언없이 사용됩니다.
"선언하지 않고 단순히 사용"란 VAR 키워드를 사용하지 않고 변수가 선언된다는 것을 의미합니다. 우리는 이미 글로벌 변수를 암시 적으로 생성하는 것을 피하는 방법이 VAR 키워드를 가능한 한 많이 선언하는 것임을 분명히했습니다.
하지만 var를 사용해도 괜찮다고 생각하십니까? 이 구덩이를 살펴 보겠습니다.
코드 사본은 다음과 같습니다.
함수 foo () {
var a = b = 0;
// 몸...
}
어쩌면 당신이 기대하는 것은 두 개의 로컬 변수 일지 모르지만 B는 실제 변수입니다. 왜? 할당 작업은 오른쪽에서 왼쪽으로이므로 다음과 같습니다.
코드 사본은 다음과 같습니다.
함수 foo () {
var a = (b = 0);
// 몸...
}
B는 글로벌 변수입니다.
구덩이를 채우십시오 : 가변 선언은 하나씩 오는 것이 가장 좋습니다. 도매를하지 마십시오 ~ _ ~;
2. 변수 선언
먼저 구덩이를 살펴 보겠습니다.
코드 사본은 다음과 같습니다.
myname = "글로벌";
함수 foo () {
경고 (myName);
var myname = "로컬";
경고 (myName);
}
foo ();
언뜻보기에, 우리는 두 개의 알림의 결과가 각각 "글로벌"및 "로컬"일 것으로 예상하지만 실제 결과는 "정의되지 않은"및 "로컬"입니다. 왜? 변수는 동일한 범위 (동일한 함수)로 선언되므로 먼저 범위의 상단에 의해 구문 분석됩니다.
따라서 위의 코드 스 니펫의 실행 동작은 다음과 같습니다.
코드 사본은 다음과 같습니다.
함수 foo () {
var myname;
경고 (myName); // "한정되지 않은"
myname = "로컬";
경고 (myName); // "현지의"
}
다른 구덩이를 사용하여 사전 전망을 실제로 이해하는지 테스트하십시오.
코드 사본은 다음과 같습니다.
if (! ( "a"in window)) {
var a = 1;
}
경고 (a);
변수 선언은 코드의 상단으로 진행되며 아직 할당되지 않았습니다. 다음으로, if 문을 입력하고 창에 "a"가 설정되었다고 판단하므로 (a는 글로벌 변수로 선언 됨) 판단 명령문 계산 결과가 거짓이되고 IF 문이 점프되므로 A의 값은 정의되지 않습니다.
코드 사본은 다음과 같습니다.
var a; // "한정되지 않은"
Console.log ( "a"창에); // 진실
if (! ( "a"in window)) {
var a = 1; // 실행되지 않았습니다
}
경고 (a); // "한정되지 않은"
구덩이를 채우십시오 : 변수 선언을 범위 상단에 수동으로 배치하는 것이 가장 좋습니다. 현재 할당 할 수없는 변수의 경우 먼저 선언 한 다음 값을 할당하는 방법을 사용할 수 있습니다.
3. 기능 선언
기능 선언은 또한 범위의 최상위로 진행되며, 표현 및 진술이 구문 분석되고 평가되기 전에 구문 분석 및 평가됩니다.
코드 사본은 다음과 같습니다.
경고 (foo 형); // "기능"
함수 foo () {
// 몸...
}
당신은 그것을 비교할 수 있습니다 :
코드 사본은 다음과 같습니다.
경고 (foo 형); // "한정되지 않은"
var foo = function () {
// 몸...
};
이 원리를 이해한다면 여전히 다음 함정에 빠질 것입니까?
코드 사본은 다음과 같습니다.
기능 test () {
경고 ( "1");
}
시험();
기능 test () {
경고 ( "2");
}
시험();
위의 코드 스 니펫을 실행할 때 보이는 팝업 창은 "2"이며 왜 "1"및 "2"가 아닌가? 매우 간단합니다. 테스트 선언은 test () 전에 구문 분석됩니다. 후자는 전자를 무시하기 때문에 두 처형의 결과는 "2"입니다.
구덩이를 채우십시오 : 대부분의 경우, 나는 기능 선언 대신 기능 표현, 특히 일부 명령문 블록에서 기능 표현을 사용합니다.
4. 기능 표현
먼저 명명 된 기능 표현식을 살펴 보겠습니다. 물론 이름은 예를 들어야합니다.
다음과 같이 코드를 복사하십시오. var bar = function foo () {
// 몸...
};
함수 이름은 내부 기능으로 만 표시됩니다. 다음 함정과 같은 :
코드 사본은 다음과 같습니다.
var bar = function foo () {
foo (); // 정상적으로 실행됩니다
};
foo (); // 오류 : 참조 오레러
구덩이를 채우십시오 : 가능한 한 적은 이름으로 명명 된 기능 표현을 사용해보십시오 (일부 재귀 및 디버깅 목적 제외). 외부에서는 기능 이름을 사용하지 마십시오.
5. 기능 자기 실행
함수 표현식의 경우 ()를 첨가하여 실행할 수 있으며, 매개 변수는 괄호 안에 전달 될 수 있지만 함수 선언은 할 수 없습니다. 피트:
코드 사본은 다음과 같습니다.
// (1) 이것은 단지 그룹화 연산자 일 뿐이며 함수 호출이 아닙니다!
// 여기의 기능이 실행되지 않았으므로 여전히 진술입니다.
함수 foo (x) {
경고 (x);
} (1);
다음 코드 스 니펫은 별도로 실행되며 팝업 창에는 "1"이 표시됩니다. (1) 이전에 함수 표현식이기 때문에 ()는 그룹화 연산자가 아니라 연산자이며 호출 실행을 나타냅니다.
다음과 같이 코드를 복사하십시오 : // 표준 익명 함수 표현식
var bar = function foo (x) {
경고 (x);
} (1);
// 이전 ()은 함수 선언을 표현식으로 변환합니다.
(함수 foo (x) {
경고 (x);
}) (1);
// 전체 ()는 표현식입니다
(함수 foo (x) {
경고 (x);
} (1));
// 새로운 표현
새로운 기능 foo (x) {
경고 (x);
} (1);
// &&, ||,!, +, -, ~ 등. 연산자 (및 쉼표) 기능 표현 및 기능 선언을 명확하게하는 연산자 (및 쉼표)
// 파서가 파서 중 하나가 표현이라는 것을 알게되면 다른 하나는 표현식에 기본적으로 기본값을 할 것입니다.
true && function foo (x) {
경고 (x);
} (1);
구덩이를 채우십시오 :이 구덩이의 핵심은 모든 종류의 기능 표현의 본질을 파악하는 것입니다.
6. 루프의 폐쇄
다음은 일반적인 함정을 보여줍니다.
코드 사본은 다음과 같습니다.
<! doctype html>
<html lang = "en">
<헤드>
<meta charset = "utf-8">
<title> 문서 </title>
</head>
<body>
<H3> 아래 링크를 클릭 할 때 시퀀스의 수를 표시하십시오 </h3>
<ul>
<li> <a href = " #"> 링크 #0 </a> </li>
<li> <a href = " #"> 링크 #1 </a> </li>
<li> <a href = " #"> 링크 #2 </a> </li>
<li> <a href = " #"> 링크 #3 </a> </li>
<li> <a href = " #"> 링크 #4 </a> </li>
</ul>
</body>
</html>
코드 사본은 다음과 같습니다.
var links = document.getElementsByTagName ( "ul") [0] .getElementsByTagName ( "a");
for (var i = 0, l = links.length; i <l; i ++) {
링크 [i] .onclick = function (e) {
e.preventDefault ();
ALERT ( "링크 #" + i를 클릭하십시오);
}
}
I-TH 링크를 클릭 할 때이 순서에서 인덱스 I의 값을 얻을 것으로 예상됩니다. 그러나 어떤 링크를 클릭하든 루프 후 I의 최종 결과를 얻습니다 : "5".
이유를 설명하십시오. 경고가 호출되면 FOR 루프의 익명 함수 표현식은 외부 변수 I (클로저)에 대한 참조를 유지합니다. 현재 루프가 끝나고 I의 값은 "5"로 수정됩니다.
구덩이를 채우십시오 : 원하는 결과를 얻으려면 각 루프에서 변수 I의 사본을 만들어야합니다. 다음은 올바른 접근법을 보여줍니다.
코드 사본은 다음과 같습니다.
<헤드>
<meta charset = "utf-8">
<title> 문서 </title>
</head>
<body>
<H3> 아래 링크를 클릭 할 때 시퀀스의 수를 표시하십시오 </h3>
<ul>
<li> <a href = " #"> 링크 #0 </a> </li>
<li> <a href = " #"> 링크 #1 </a> </li>
<li> <a href = " #"> 링크 #2 </a> </li>
<li> <a href = " #"> 링크 #3 </a> </li>
<li> <a href = " #"> 링크 #4 </a> </li>
</ul>
</body>
</html>
코드 사본은 다음과 같습니다.
var links = document.getElementsByTagName ( "ul") [0] .getElementsByTagName ( "a");
for (var i = 0, l = links.length; i <l; i ++) {
링크 [i] .onclick = (function (index) {
반환 함수 (e) {
e.preventDefault ();
ALERT ( "링크 #" + index를 클릭);
}
})(나);
}
보시다시피 (function () {...}) ()의 형태는 위에서 언급 한 함수의 자체 실행입니다. 나는 매개 변수로 인덱스로 전달됩니다. Alert가 다시 실행되면 Index에 대한 참조가 있습니다. 현재이 값은 루프에 의해 변경되지 않습니다. 물론 원칙을 이해 한 후에는 다음과 같이 쓸 수도 있습니다.
코드 사본은 다음과 같습니다.
for (var i = 0, l = links.length; i <l; i ++) {
(기능 (색인) {
링크 [i] .onclick = function (e) {
e.preventDefault ();
ALERT ( "링크 #" + index를 클릭);
}
})(나);
}
그것은 또한 작동합니다.