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

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

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

先上三段說(shuō)明作用域的代碼

//==========例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],如果不能答對(duì)說(shuō)明你對(duì)javascript的作用域特性還未理解透徹。

什么是作用域?

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

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

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

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

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

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

2.javascript變量的作用域:

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

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

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

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

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

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

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

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

201675145052363.jpg (398×180)

變量對(duì)象(Variable Object)、活動(dòng)對(duì)象(Activation Object)和Arguments對(duì)象(Arguments Object)

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

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

2.解析器處理代碼時(shí)的兩個(gè)階段

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

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

舉兩個(gè)好吃的栗子:

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

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

201675145144397.jpg (476×190)

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

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

201675145319913.jpg (476×204)

3.作用域鏈(Scope Chain)

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

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?整個(gè)過(guò)程是怎么發(fā)生的呢?請(qǐng)看下圖。

201675145344904.jpg (608×272)

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

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

201675145416219.jpg (631×370)

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

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

相關(guān)文章

最新評(píng)論