類 C 語言一般都用于塊級作用域,但是Javascript中的 while, if-else, for, switch-case 等控制結構不具有自己的作用域,
在Javascript中隻有函數(function)具有自己的作用域,請比較如下的 C# 代碼和 Javascript 代碼:
// C# 中 for 循環有自己的作用域
for ( int i = 0 ; i < 5 ; i ++ )
{
//
}
Console.WriteLine(i); // 目前上下文中不存在名稱“i”
// Javascript中 for 循環沒有自己的作用域
for ( var i = 0 ; i < 5 ; i ++ ) {
// do something
}
console.log(i); // 5
但是,Javascript中的函數有自己的作用域,如下示例:
// function 擁有自己的作用域
( function () {
var j = 6 ;
})();
console.log( typeof (j)); // 'undefined'
// function 中使用和全局變量相同名稱的局部變量
var i = 5 ;
( function () {
var i = 1 ;
})();
console.log(i); // 5
在函數中不使用 var 關鍵字聲明的變量,就會在全局範圍内查找,如下:
var i = 5 ;
( function () {
i ++ ; // 此時的i是全局變量
})();
console.log(i); // 6
這裡就有一個可能讓人迷惑的代碼,如下:
var i = 6 ;
( function () {
i ++ ; // 此時的i是局部變量,但是未定義(undefined),undefined + 1 == NaN
console.log(isNaN(i)); // true
var i;
})();
console.log(i); // 6
或許你會覺得函數中 i++, 引用的豈不是全部變量?
答案是否定的,隻要在函數内擁有相同名稱的局部變量定義,那這個變量就是局部的。
那我們如何在函數内引用和局部變量相同名稱的全局變量呢?
答案是使用命名字首。考慮如下代碼:
var i = 6 ;
( function () {
window.i ++ ; // 此時的i是局部變量
var i = 1 ;
})();
console.log(i); // 7
正因為自執行的匿名函數,可以用來向外部隐藏屬性,我們可以用這個特性在Javascript中實作私有屬性。
考慮如下擷取随機數([0,10])的對象:
var random1 = {
_num: - 1 ,
_init: function () {
// 随機一個大于等于0,小于等于10的整數
this ._num = Math.round(Math.random() * 10 );
},
getNum: function () {
if ( this ._num === - 1 ) {
this ._init();
}
return this ._num;
}
};
console.log( ' random1._num == ' + random1._num); // -1
console.log( ' random1.getNum() == ' + random1.getNum()); // [0,10]
雖然我們的意圖是想向外界隐藏 _num 變量和 _init 屬性,不過這個目的顯然沒有達到,使用者仍然可以通過 random1._init(); 的方式調用。
我們需要是用Javascript中函數特有的性質(擁有自己的作用域),使用自執行的匿名函數來達到隐藏屬性的目的。
考慮如下解決辦法:
var random2 = {};
( function () {
var _num = - 1 ;
function _init() {
_num = Math.round(Math.random() * 10 );
}
random2.getNum = function () {
if (_num === - 1 ) {
_init();
}
return _num;
};
})();
console.log( ' random2._num == ' + random2._num); // 'undefined'
console.log( ' random2.getNum() == ' + random2.getNum()); // [0,10]
代碼下載下傳