国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

JavaScript.The.Good.Parts閱讀筆記(二)作用域&閉包&減緩全局空間污染

2019-11-21 00:08:09
字體:
來源:轉載
供稿:網友
如代碼塊
復制代碼 代碼如下:

if (true) {
int i = 100;
}
print(i); //錯誤,變量i沒有聲明

如上面例子所示,代碼塊外的函數是無法訪問i變量的。
但在javaScript里,情況則完全不同。
復制代碼 代碼如下:

if (true) {
var i = 100;
}
alert(i); //彈出框并顯示100

很多現代語言都推薦盡可能遲地聲明變量,但在Javascript里這是一個最糟糕的建議。由于缺少塊級作用域,最好在函數體的頂部聲明函數中可能用到的所有變量。


閉包特性:
雖然缺少塊級作用域,但是函數的作用域還是存在的。
這種作用域有一個好處,就是內部函數可以訪問定義它們的外部函數的參數和變量(除了this和argument)。
利用這種特性,則可以這樣來設計代碼。
復制代碼 代碼如下:


var bankAccount = function () {
var value = 0;
return {
deposit: function (inc) {
value += inc;
},
getValue: function (){
return value;
}
}
}


var myAccount = bankAccount(); //新開一個銀行賬戶
myAccount.deposit(1000); //存1000塊進去
alert(myAccount.getValue()); //should alert(1000);


value由于在bankAccount這個function里,外部無法對它進行直接操作,必須通過bankAccount function給他返回的對象來進行操作,通過這樣來實現C#和java里的private的字段。

減緩全局變量污染全局空間:利用函數的作用域,我們在寫js庫的時候可以減少跟其他庫沖突。
復制代碼 代碼如下:

(function () {
var hello = 'Hello World.';
})();
alert(hello); //error: hello no exist.

這里的語法很有點詭異,主要思想是定義一個匿名方法,并且馬上執行。由于function開頭這個litertal會被解釋作為函數定義,這里加上了一對括號包住它,然后再用一對括號表示調用此函數。外部的alert訪問不到在函數內部定義的hello。


陷阱一:var的陷阱

“減緩全局變量污染全局空間”的例子改成
復制代碼 代碼如下:

(function () {
hello = 'Hello World.'; //remove var
})();
alert(hello); //alert ('Hello World.');

當變量hello沒有用var顯式聲明時,hello成為了一個全局變量!!

雖然利用這個特性,咱們可以提供一個對外接口,但不建議這樣做。
復制代碼 代碼如下:

(function () {
var hello = 'Hello World.';
sayHello = function () { //不建議采用這種方式來提供接口,看起來很不明顯。
alert(hello);
}
})();
sayHello();

可以改進為
復制代碼 代碼如下:

(function (window) {
var hello = 'Hello World.';
window.$ = {
sayHello: function () {
alert(hello);
}
};
})(window);
$.sayHello(); //看起來像jQuery那么酷



復制代碼 代碼如下:

var obj = (function () {
var hello = 'Hello World.';
return {
sayHello: function () {
alert(hello);
}
};
})();
obj.sayHello();


陷阱二: 閉包的陷阱

復制代碼 代碼如下:

(function () { //函數a
var arr = [];
  var i = 0;
var j;
for ( ; i < 3; i++) {
arr.push(function () { //函數b
alert(i * 10);
});
}


for (j in arr) {
arr[j]();
}
})();


原以為函數數組arr里各個函數執行后,會彈出0,10,20,但是結果不是如此。結果是彈出30,30,30。
函數b訪問的不是當時的 i的值, 而是直接訪問變量i(用于都是取i最新的值)。
原因是函數b是函數a的內部函數,變量i對函數b是可見的,函數b每次都從i處獲取最新的值。

這次改成:
復制代碼 代碼如下:

(function () { //函數a
var arr = [];
var i = 0;
  var j;
for ( ; i < 3; i++) {
arr.push((function (anotherI) { //函數m
return function () { //函數b
alert(anotherI * 10);
}
})(i)); // 此處為(function b(anotherI) {})(i)
}


for (j in arr) {
arr[j]();
}
})();

這次執行后,終于彈出0,10,20。這是為什么呢。

函數b訪問的是anotherI(當時的i的值),而不是直接訪問變量i。
每次在arr.push前,都會定義一個新匿名的函數m。本例中定義了3個匿名函數m0,m1,m2,每當被調用后,他們的anotherI都得到當前i的值。每個m函數執行后都返回一個b函數。b0在m0里,b1在m1里,b2在m2里。b0只能訪問m0的anotherI(為0),而b0訪問不了m1的anotherI,因為m0和m1為不同的函數。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 五常市| 隆林| 孟连| 河源市| 吴江市| 诸城市| 福泉市| 建宁县| 安塞县| 宿迁市| 喀喇沁旗| 墨脱县| 和田县| 和顺县| 石台县| 南岸区| 荣成市| 洞头县| 张家口市| 铜川市| 灵璧县| 景德镇市| 寿宁县| 凤凰县| 武汉市| 台北县| 上思县| 科技| 孟州市| 宁南县| 涿州市| 辽源市| 聂拉木县| 兰州市| 凌云县| 靖州| 鹰潭市| 高青县| 鄄城县| 孝昌县| 左贡县|