欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

結(jié)合代碼圖文講解JavaScript中的作用域與作用域鏈

 更新時間:2016年07月05日 14:59:21   作者:DenGo  
JavaScript雖然沒有類,但變量和一些函數(shù)卻同樣擁有局部作用域的制約,下面結(jié)合代碼圖文講解JavaScript中的作用域與作用域鏈:

先上三段說明作用域的代碼

//==========例1==========
 
var scope='global';
function fn(){
  alert(scope);
  var scope='local';
  alert(scope);
}
fn();    //輸出結(jié)果?
alert(scope);//輸出結(jié)果?
 
//===========例2==========
 
var scope='global';
function fn(){
  alert(scope);
  scope='local';
  alert(scope);
}
fn();    //輸出結(jié)果?
alert(scope);//輸出結(jié)果?
 
//===========例3=========
 
var scope='global';
function fn(scope){
  alert(scope);
  scope='local';
  alert(scope);
}
fn();    //輸出結(jié)果?
alert(scope);//輸出結(jié)果?

這三段代碼只有小許差異,但結(jié)果缺截然不同,例1分別輸出[undefined , local , global],例2分別輸出[global , local , local],例3結(jié)果輸出[undefined , local , global],如果不能答對說明你對javascript的作用域特性還未理解透徹。

什么是作用域?

也許有人會問:變量a的作用域是什么?一會兒又問:函數(shù)a的作用域是什么?變量和函數(shù)的作用域分別是啥玩意?

我們先來看看“作用域”是什么意思,“作用域”拆開來就是“作用”和“域”

  • 作用:訪問、操作、調(diào)用……
  • 域:區(qū)域、范圍、空間……

作用域就是變量和函數(shù)的可訪問范圍,或者說變量或函數(shù)起作用的區(qū)域。

1.javascript函數(shù)的作用域:

函數(shù)內(nèi)的區(qū)域,就是這個函數(shù)的作用域,變量和函數(shù)在這個區(qū)域都可以訪問操作。最外層函數(shù)外的區(qū)域叫全局作用域,函數(shù)內(nèi)的區(qū)域叫局部作用域。

2.javascript變量的作用域:

在源代碼中變量所在的區(qū)域,就是這個變量的作用域,變量在這個區(qū)域內(nèi)可以被訪問操作。在全局作用域上定義的變量叫全局變量,在函數(shù)內(nèi)定義的變量叫局部變量。

簡單地理解,JS源代碼被函數(shù){ }劃分成一塊一塊的區(qū)域,這些區(qū)域換個身份就是某函數(shù)或某變量的作用域,變量的作用域和函數(shù)的作用域在源代碼中有可能指的是同一塊區(qū)域。

作用域鏈
作用域鏈(Scope Chain)是javascript內(nèi)部中一種變量、函數(shù)查找機制,它決定了變量和函數(shù)的作用范圍,即作用域,理解作用域鏈的作用原理,上一篇文章的三個例子也就能理解了,從而知其然也知其所以然。

作用域鏈是ECMAScript-262說明文檔中的概念,javascript引擎是按ECMAScript-262說明文檔去實現(xiàn)的,了解javascript引擎的工作原理有利于我們理解javascript的特性,但絕大多數(shù)js程序員不會去了解非常底層的技術(shù),所以閱讀ECMAScript-262說明文檔,我們可以有一個直觀的方式去模擬javascript引擎的工作原理。

本文將通過1999年的ECMAScript-262-3th第三版來說明作用域鏈的形成原理,將會介紹執(zhí)行環(huán)境,變量對象和活動對象,arguments對象,作用域鏈等幾個概念。2009年發(fā)布了ECMAScript-262-5th第五版,不同的是取消了變量對象和活動對象等概念,引入了詞法環(huán)境(Lexical Environments)、環(huán)境記錄(EnviromentRecord)等新的概念,所以兩個版本的概念不要混淆了。

1.執(zhí)行環(huán)境(Execution Contexts)

執(zhí)行環(huán)境(Execution Contexts)也被翻譯為執(zhí)行上下文,當解析器進入ECMAScript的可執(zhí)行代碼,解析器就進入一個執(zhí)行環(huán)境,活動的執(zhí)行環(huán)境組成一個邏輯上的棧,在這個邏輯棧頂部的執(zhí)行環(huán)境是當前運行的執(zhí)行環(huán)境。

注:ECMAScript中有三種可執(zhí)行代碼,Global、Function和Eval,全局環(huán)境即是Global可執(zhí)行代碼,函數(shù)即是Function可執(zhí)行代碼。邏輯棧是一種特殊的數(shù)據(jù)存儲格式,特點是‘先進后出,后進先出',添加數(shù)據(jù)會先壓入邏輯棧頂部,刪除數(shù)據(jù)必須先從頂部開始刪除。

201675145052363.jpg (398×180)

變量對象(Variable Object)、活動對象(Activation Object)和Arguments對象(Arguments Object)

每個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的變量對象,當解析器進入執(zhí)行環(huán)境時,就會創(chuàng)建一個變量對象,變量對象保存著在當前執(zhí)行環(huán)境中聲明的變量和函數(shù)的引用。

變量對象是一個抽象的概念,在不同的執(zhí)行環(huán)境中,變量對象有不同的身份,在解析器進入任何執(zhí)行環(huán)境之前,就已經(jīng)創(chuàng)建了一個Global對象,當解析器進入全局執(zhí)行環(huán)境時,Global對象就充當變量對象,當解析器進入一個函數(shù)時,就會創(chuàng)建一個活動對象充當變量對象。

2.解析器處理代碼時的兩個階段

我們都知道javascript解析器是一段一段解析處理代碼的,為毛?這就要涉及解析器處理代碼時的兩個階段,解析代碼和執(zhí)行代碼。

當解析器進入執(zhí)行環(huán)境時,變量對象就會添加執(zhí)行環(huán)境中聲明的變量和函數(shù)作為它的屬性,這就意味著變量和函數(shù)在聲明之前已經(jīng)可用,變量值為undefined,這就是變量和函數(shù)聲明提升(Hoisting)的原因,與此同時作用域鏈和this確定,此過程為解析階段,俗稱預解析。接著解析器開始執(zhí)行代碼,為變量添加相應值的引用,得到執(zhí)行結(jié)果,此過程為執(zhí)行階段。

舉兩個好吃的栗子:

var a=123;
var b="abc";
function c(){
  alert('11');
}

上述全局環(huán)境中的代碼解析執(zhí)行后,會將Global對象作為變量對象,保存以下數(shù)據(jù)。

201675145144397.jpg (476×190)

function testFn(a){
  var b="123";
  function c(){
    alert("abc");
  }
}
 
testFn(10);

當解析器進入函數(shù)執(zhí)行環(huán)境時,則會創(chuàng)建一個活動對象作為變量對象,活動對象還會創(chuàng)建一個Arguments對象,arguments對象是一個參數(shù)集合,用來保存參數(shù),這就是我們寫函數(shù)時可以使用arguments[0]等來使用參數(shù)的原因。

201675145319913.jpg (476×204)

3.作用域鏈(Scope Chain)

每個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的作用域鏈,當解析器進入執(zhí)行環(huán)境時被定義,作用域鏈是一個對象列表,用來檢索各個變量對象中的變量和函數(shù),這樣可以保證執(zhí)行環(huán)境有權(quán)訪問哪些變量和函數(shù),舉個栗子。

var a='123';
function testFn(b){
  var c='abc';
 
  function testFn2(){
    var d='efg';
    alert(a);
  }
 
  testFn2();
}
 
testFn(10);

testFn2內(nèi)未聲明變量a,為什么testFn2能調(diào)用全局變量a?整個過程是怎么發(fā)生的呢?請看下圖。

201675145344904.jpg (608×272)

當解析器進入全局執(zhí)行環(huán)境時,調(diào)用變量和函數(shù)時只在Global對象中查找。

當解析器進入testFn函數(shù)執(zhí)行環(huán)境時,函數(shù)內(nèi)部屬性[[scope]]中首先填入Global對象,然后將testFn活動對象添加到Global對象之前,形成一個作用域鏈。

201675145416219.jpg (631×370)

當解析器進入testFn2函數(shù)執(zhí)行環(huán)境時,函數(shù)內(nèi)部屬性[[scope]]首先填入父級的作用域鏈,然后再將當前的testFn2活動對象添加到作用域鏈的前端,形成一個新的作用域鏈。

testFn2調(diào)用變量a時,首先在當前的testFn2活動對象中查找,如果沒有找到就順著作用域鏈向上,在testFn活動對象中查找變量a,如果沒有找到再順著作用域鏈向上查找,直到在最后Global對象中找到為止,否則報錯。所以函數(shù)內(nèi)部可以調(diào)用外部環(huán)境的變量,外部環(huán)境不能調(diào)用函數(shù)內(nèi)部的變量,這就是作用域特性的原理。

相關(guān)文章

最新評論