首頁  >  文章  >  web前端  >  介紹JavaScript變數作用域實例

介紹JavaScript變數作用域實例

零下一度
零下一度原創
2017-06-28 13:47:211240瀏覽

這篇文章主要介紹了JavaScript變數作用域,小編覺得蠻不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧

在JavaScript中,用var申明的變數其實是有作用域的。

如果一個變數在函數體內部申明,則該變數的作用域為整個函數體,在函數體外不可引用該變數:


'use strict';

function foo() {
  var x = 1;
  x = x + 1;
}

x = x + 2; // ReferenceError! 无法在函数体外引用变量x

如果兩個不同的函數各自申明了同一個變量,那麼該變數只在各自的函數體內運作。換句話說,不同函數內部的同名變數互相獨立,不影響:


'use strict';

function foo() {
  var x = 1;
  x = x + 1;
}

function bar() {
  var x = 'A';
  x = x + 'B';
}

由於JavaScript的函數可以嵌套,此時,內部函數可以存取外部函數定義的變量,反過來則不行:


'use strict';

function foo() {
  var x = 1;
  function bar() {
    var y = x + 1; // bar可以访问foo的变量x!
  }
  var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}

如果內部函數和外部函數的變數名稱重名怎麼辦?


'use strict';

function foo() {
  var x = 1;
  function bar() {
    var x = 'A';
    alert('x in bar() = ' + x); // 'A'
  }
  alert('x in foo() = ' + x); // 1
  bar();
}

這表示JavaScript的函數在尋找變數時從自身函數定義開始,並從「內」向「外」尋找。如果內部函數定義了與外部函數重名的變量,則內部函數的變數將「屏蔽」外部函數的變數。

變數提升

JavaScript的函數定義有個特點,它會先掃描整個函數體的語句,把所有申明的變數「提升」到函數頂部:


'use strict';

function foo() {
  var x = 'Hello, ' + y;
  alert(x);
  var y = 'Bob';
}

foo();

雖然是strict模式,但語句var x = 'Hello, ' + y;並傳錯,原因是變數y稍後申明了。但是alert顯示Hello, undefined,說明變數y的值為undefined。這正是因為JavaScript引擎自動提升了變數y的聲明,但不會提升變數y的賦值。

對於上述foo()函數,JavaScript引擎看到的程式碼相當於:


##

function foo() {
  var y; // 提升变量y的申明
  var x = 'Hello, ' + y;
  alert(x);
  y = 'Bob';
}

由於JavaScript的這個怪異的“特性”,我們在函數內部

定義變數時,請嚴格遵守“在函數內部首先申明所有變數”這一規則。最常見的做法是用一個var申明函數內部用到的所有變數:


function foo() {
  var
    x = 1, // x初始化为1
    y = x + 1, // y初始化为2
    z, i; // z和i为undefined
  // 其他语句:
  for (i=0; i<100; i++) {
    ...
  }
}

全域作用域

不在任何函數內定義的變數就具有全域作用域。實際上,JavaScript預設有一個全域物件

window,全域作用域的變數實際上被綁定到window的一個屬性:


&#39;use strict&#39;;

var course = &#39;Learn JavaScript&#39;;
alert(course); // &#39;Learn JavaScript&#39;
alert(window.course); // &#39;Learn JavaScript&#39;

因此,直接存取全域變數

course和存取window.course是完全一樣的。

你可能猜到了,由於函數定義有兩種方式,以變量方式

var foo = function () {}#定義的函數實際上也是一個全域變量,因此,頂層函數的定義也被視為一個全域變量,並綁定到window物件:


&#39;use strict&#39;;

function foo() {
  alert(&#39;foo&#39;);
}

foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用

進一步大膽地猜測,我們每次直接呼叫的alert()函數其實也是window的變數:



&#39;use strict&#39;;

window.alert(&#39;调用window.alert()&#39;);
// 把alert保存到另一个变量:
var old_alert = window.alert;
// 给alert赋一个新函数:
window.alert = function () {}

// 恢复alert:
window.alert = old_alert;
alert(&#39;又可以用alert()了!&#39;);

這表示JavaScript其實只有一個全域作用域。任何變數(函數也視為變數),如果沒有在目前

函數作用域中找到,就會繼續往上查找,最後如果在全域作用域中也沒有找到,則報ReferenceError錯誤。

名字空間

全域變數會綁定到

window上,不同的JavaScript檔案如果使用了相同的全域變量,或定義了相同名字的頂層函數,都會造成命名衝突,而且很難被發現。

減少衝突的一個方法是把自己的所有變數和函數全部綁定到一個全域變數。例如:



// 唯一的全局变量MYAPP:
var MYAPP = {};

// 其他变量:
MYAPP.name = &#39;myapp&#39;;
MYAPP.version = 1.0;

// 其他函数:
MYAPP.foo = function () {
  return &#39;foo&#39;;
};

把自己的程式碼全部放入唯一的名字空間

MYAPP中,會大幅減少全域變數衝突的可能性。

許多著名的JavaScript函式庫都是這麼幹的:jQuery,YUI,underscore等等。


局部作用域

由於JavaScript的變數作用域實際上是函數內部,我們在

for循環等語句區塊中是無法定義具有局部作用域的變數的:


&#39;use strict&#39;;

function foo() {
  for (var i=0; i<100; i++) {
    //
  }
  i += 100; // 仍然可以引用变量i
}

為了解決區塊級作用域,ES6引入了新的關鍵字let,用let替代var可以申明一個區塊級作用域的變數:



&#39;use strict&#39;;

function foo() {
  var sum = 0;
  for (let i=0; i<100; i++) {
    sum += i;
  }
  i += 1; // SyntaxError
}

常數
#

由于varlet申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”:


var PI = 3.14;

ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:


&#39;use strict&#39;;

const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14

以上是介紹JavaScript變數作用域實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn