JavaScript代碼編寫(xiě)中各種各樣的坑和填坑方法
坑”這個(gè)字,在此的意思是“陷阱”。由于 JavaScript “弱語(yǔ)言”的性質(zhì),使得其在使用過(guò)程中異常的寬松靈活,但也極為容易“中招”。這些坑往往隱藏著,所以必須擦亮雙眼,才能在學(xué)習(xí)與應(yīng)用 JS 的道路上走的一帆風(fēng)順。
一、全局變量
JavaScript 通過(guò)函數(shù)管理作用域。在函數(shù)內(nèi)部聲明的變量只在這個(gè)函數(shù)內(nèi)部,函數(shù)外面不可用。另一方面,全局變量就是在任何函數(shù)外面聲明的或是未聲明直接簡(jiǎn)單使用的。
“未聲明直接簡(jiǎn)單使用”,指的是不用 var 關(guān)鍵字來(lái)聲明變量。這個(gè)我們已經(jīng)非常清楚,避免造成隱式產(chǎn)生全局變量的方法就是聲明變量盡量用 var 關(guān)鍵字。
可你以為用了 var 就 ok 了?來(lái)看看這個(gè)坑:
function foo() {
var a = b = 0;
// body...
}
也許你期望得到的是兩個(gè)局部變量,但 b 卻是貨真價(jià)實(shí)的全局變量。why? Because 賦值運(yùn)算是自右往左的 ,所以這相當(dāng)于:
function foo() {
var a = (b = 0);
// body...
}
所以 b 是全局變量。
填坑:變量聲明,最好一個(gè)個(gè)來(lái),別搞批發(fā)~_~;
二、變量聲明
先來(lái)看坑:
myName = "global";
function foo() {
alert(myName);
var myName = "local";
alert(myName);
}
foo();
乍看上去,我們預(yù)計(jì)期望兩次 alert 的結(jié)果分別為 “global” 與 “l(fā)ocal”,但真實(shí)的結(jié)果是 “undefined” 與 “l(fā)ocal”。why? Because 變量在同一作用域(同一函數(shù))中,聲明都是被提至作用域頂部先進(jìn)行解析的。
所以以上代碼片段的執(zhí)行行為可能就像這樣:
function foo() {
var myName;
alert(myName); // "undefined"
myName = "local";
alert(myName); // "local"
}
用另一個(gè)坑來(lái)測(cè)試下你是否真的理解了預(yù)解析:
if (!("a" in window)) {
var a = 1;
}
alert(a);
a 變量的聲明被提前到了代碼頂端,此時(shí)還未賦值。接下來(lái)進(jìn)入 if 語(yǔ)句,判斷條件中 "a" in window 已成立(a 已被聲明為全局變量),所以判斷語(yǔ)句計(jì)算結(jié)果為 false,直接就跳出 if 語(yǔ)句了,所以 a 的值為 undefined。
var a; // "undefined"
console.log("a" in window); // true
if (!("a" in window)) {
var a = 1; // 不執(zhí)行
}
alert(a); // "undefined"
填坑:變量聲明,最好手動(dòng)置于作用域頂部,對(duì)于無(wú)法當(dāng)下賦值的變量,可采取先聲明后賦值的手法。
三、函數(shù)聲明
函數(shù)聲明也是被提前至作用域頂部,先于任何表達(dá)式和語(yǔ)句被解析和求值的
alert(typeof foo); // "function"
function foo() {
// body...
}
可以對(duì)比一下:
alert(typeof foo); // "undefined"
var foo = function () {
// body...
};
明白了這個(gè)道理的你,是否還會(huì)踩以下的坑呢?
function test() {
alert("1");
}
test();
function test() {
alert("2");
}
test();
運(yùn)行以上代碼片段,看到的兩次彈窗顯示的都是 “2”,為什么不是分別為 “1” 和 “2” 呢?很簡(jiǎn)單,test 的聲明先于 test() 被解析,由于后者覆蓋前者,所以兩次執(zhí)行的結(jié)果都是 “2”。
填坑:多數(shù)情況下,我用函數(shù)表達(dá)式來(lái)代替函數(shù)聲明,特別是在一些語(yǔ)句塊中。
四、函數(shù)表達(dá)式
先看命名函數(shù)表達(dá)式,理所當(dāng)然,就是它得有名字,例如:
// body...
};
要注意的是:函數(shù)名只對(duì)其函數(shù)內(nèi)部可見(jiàn)。如以下坑:
var bar = function foo() {
foo(); // 正常運(yùn)行
};
foo(); // 出錯(cuò):ReferenceError
填坑:盡量少用命名函數(shù)表達(dá)式(除了一些遞歸以及 debug 的用途),切勿將函數(shù)名使用于外部。
五、函數(shù)的自執(zhí)行
對(duì)于函數(shù)表達(dá)式,可以通過(guò)后面加上 () 自執(zhí)行,而且可在括號(hào)中傳遞參數(shù),而函數(shù)聲明不可以??樱?BR>
// (1) 這只是一個(gè)分組操作符,不是函數(shù)調(diào)用!
// 所以這里函數(shù)未被執(zhí)行,依舊是個(gè)聲明
function foo(x) {
alert(x);
}(1);
以下代碼片段分別執(zhí)行都彈窗顯示 “1”,因?yàn)樵?(1) 之前,都為函數(shù)表達(dá)式,所以這里的 ()非分組操作符,而為運(yùn)算符,表示調(diào)用執(zhí)行。
var bar = function foo(x) {
alert(x);
}(1);
// 前面的 () 將 function 聲明轉(zhuǎn)化為了表達(dá)式
(function foo(x) {
alert(x);
})(1);
// 整個(gè) () 內(nèi)為表達(dá)式
(function foo(x) {
alert(x);
}(1));
// new 表達(dá)式
new function foo(x) {
alert(x);
}(1);
// &&, ||, !, +, -, ~ 等操作符(還有逗號(hào)),在函數(shù)表達(dá)式和函數(shù)聲明上消除歧義
// 所以一旦解析器知道其中一個(gè)已經(jīng)是表達(dá)式了,其它的也都默認(rèn)為表達(dá)式了
true && function foo(x) {
alert(x);
}(1);
填坑:這個(gè)坑的關(guān)鍵在于,弄清楚形形色色函數(shù)表達(dá)式的實(shí)質(zhì)。
六、循環(huán)中的閉包
以下演示的是一個(gè)常見(jiàn)的坑:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h3>when clicking links below, show the number of its sequence</h3>
<ul>
<li><a href="#">link #0</a></li>
<li><a href="#">link #1</a></li>
<li><a href="#">link #2</a></li>
<li><a href="#">link #3</a></li>
<li><a href="#">link #4</a></li>
</ul>
</body>
</html>
var links = document.getElementsByTagName("ul")[0].getElementsByTagName("a");
for (var i = 0, l = links.length; i < l; i++) {
links[i].onclick = function (e) {
e.preventDefault();
alert("You click link #" + i);
}
}
我們預(yù)期當(dāng)點(diǎn)擊第 i 個(gè)鏈接時(shí),得到此序列索引 i 的值,可實(shí)際無(wú)論點(diǎn)擊哪個(gè)鏈接,得到的都是 i 在循環(huán)后的最終結(jié)果:”5”。
解釋一下原因:當(dāng) alert 被調(diào)用時(shí),for 循環(huán)內(nèi)的匿名函數(shù)表達(dá)式,保持了對(duì)外部變量 i的引用(閉包),此時(shí)循環(huán)已結(jié)束,i 的值被修改為 “5”。
填坑:為了得到想要的結(jié)果,需要在每次循環(huán)中創(chuàng)建變量 i 的拷貝。以下演示正確的做法:
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h3>when clicking links below, show the number of its sequence</h3>
<ul>
<li><a href="#">link #0</a></li>
<li><a href="#">link #1</a></li>
<li><a href="#">link #2</a></li>
<li><a href="#">link #3</a></li>
<li><a href="#">link #4</a></li>
</ul>
</body>
</html>
var links = document.getElementsByTagName(“ul”)[0].getElementsByTagName(“a”);
for (var i = 0, l = links.length; i < l; i++) {
links[i].onclick = (function (index) {
return function (e) {
e.preventDefault();
alert("You click link #" + index);
}
})(i);
}
可以看到,(function () { ... })() 的形式,就是上文提到的 函數(shù)的自執(zhí)行 ,i 作為參數(shù)傳給了 index,alert 再次執(zhí)行時(shí),它就擁有了對(duì) index 的引用,此時(shí)這個(gè)值是不會(huì)被循環(huán)改變的。當(dāng)然,明白了其原理后,你也可以這樣寫(xiě):
for (var i = 0, l = links.length; i < l; i++) {
(function (index) {
links[i].onclick = function (e) {
e.preventDefault();
alert("You click link #" + index);
}
})(i);
}
It works too.
- JavaScript字符串轉(zhuǎn)數(shù)字的5種方法及遇到的坑
- 使用PHP json_decode可能遇到的坑與解決方法
- 基于js粘貼事件paste簡(jiǎn)單解析以及遇到的坑
- JavaScript中使用typeof運(yùn)算符需要注意的幾個(gè)坑
- Javascript中構(gòu)造函數(shù)要注意的一些坑
- JS大坑之19位數(shù)的Number型精度丟失問(wèn)題詳解
- JS面試題大坑之隱式類型轉(zhuǎn)換實(shí)例代碼
- 對(duì)象題目的一個(gè)坑 理解Javascript對(duì)象
- 弱類型語(yǔ)言javascript開(kāi)發(fā)中的一些坑實(shí)例小結(jié)【變量、函數(shù)、數(shù)組、對(duì)象、作用域等】
相關(guān)文章
基于js里調(diào)用函數(shù)時(shí),函數(shù)名帶括號(hào)和不帶括號(hào)的區(qū)別
下面小編就為大家?guī)?lái)一篇基于js里調(diào)用函數(shù)時(shí),函數(shù)名帶括號(hào)和不帶括號(hào)的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07JavaScript 聯(lián)動(dòng)的無(wú)限級(jí)封裝類,數(shù)據(jù)采用非Ajax方式,隨意添加聯(lián)動(dòng)
JavaScript 聯(lián)動(dòng)的無(wú)限級(jí)封裝類,數(shù)據(jù)采用非Ajax方式,隨意添加聯(lián)動(dòng)2010-06-06談?wù)凧avaScript中super(props)的重要性
今天小編就為大家分享一篇關(guān)于談?wù)凧avaScript中super(props)的重要性,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02短視頻(douyin)去水印工具的實(shí)現(xiàn)代碼
這篇文章主要介紹了市面上短視頻(douyin)"去水印"的工具原來(lái)是這樣實(shí)現(xiàn)的,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03JS+CSS相對(duì)定位實(shí)現(xiàn)的下拉菜單
這篇文章主要介紹了JS+CSS相對(duì)定位實(shí)現(xiàn)的下拉菜單,涉及JavaScript結(jié)合css的定位技術(shù)實(shí)現(xiàn)下拉菜單的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10