<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      Javascript Context和Scope的一些學習總結

      1.1.1 摘要

      在我們學習Javascript過程中,常常會遇到作用域(Scope)和執(zhí)行上下文(Context)等概念。其中,執(zhí)行上下文與this關鍵字的關系密切。

      有面向對象編程經(jīng)驗的各位,對于this關鍵字再熟悉不過了,因此我們很容易地把它和面向對象的編程方式聯(lián)系在一起,它指向利用構造器新創(chuàng)建出來的對象;在ECMAScript中,也支持this,然而, 正如大家所熟知的,this不僅僅只用來表示創(chuàng)建出來的對象。

      在接下來的博文我們講介紹Javascript的作用域和執(zhí)行上下文,以及它們的異同之處。

      目錄

      1.1.2 正文

      執(zhí)行環(huán)境(Execution context)也稱為“環(huán)境”是Javascript中最為重要的一個概念。執(zhí)行環(huán)境定義了變量或函數(shù)有權訪問的其他數(shù)據(jù),決定了它們各自的行為。每個執(zhí)行環(huán)境都有一個與之關聯(lián)的變量對象,環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中。

      看到了執(zhí)行環(huán)境的定義有點頭昏了,簡而言之“每個執(zhí)行環(huán)境都有一個與之關聯(lián)的變量對象”;這里我們有一個疑問就是這個變量對象是怎樣定義的呢?

      接下來,讓我們看一下變量對象的定義,具體實現(xiàn)如下:

      /**
       * Execution context skeleton.
       */
      activeExecutionContext = {
          // variable object.
          VO: {...},
          this: thisValue
      };

      通過上面的偽代碼我們知道對象字面量activeExecutionContext,它包含一個變量對象VO和this屬性。

      這說明了this與上下文的可執(zhí)行代碼類型有關,其值在進入上下文階段就確定了,并且在執(zhí)行代碼階段是不能改變的(關于this使用可以閱讀《Javascript this 的一些學習總結》)。

      作用域(Scope)控制著變量和參數(shù)的可見性及生命周期。

      簡而言之,執(zhí)行環(huán)境是基于對象的,而作用域是基于函數(shù)的。

      作用域

      我們將通過一個例子介紹作用域的使用,首先,我們定義了一個函數(shù)FooA()和FooB,示例代碼如下:

      /**
       * Defines a function.
       */
      var FooA = function(){
          var a = 1;
          var FooB = function(){
              var b = 2;
              console.log(a, b); // outputs: 1, 2
          }
          console.log(a, b); // Error! b is not defined
      }
      FooA();

      在示例中,第二個log輸出變量為未定義,這是由于在Javascript中定義在函數(shù)里面的參數(shù)和變量在函數(shù)外部是不可見的,而在一個函數(shù)內部任何位置定義的參數(shù)和變量,在該函數(shù)內部任何地方都是可見的。

      執(zhí)行環(huán)境

      首先,我們定義了對象字面量o,它包含一個屬性x和方法m(),示例代碼如下:

      /**
       * Defines a literal object.
       * @type {Object}
       */
      var o = {
          x:23,
          m: function(){
              var x = 1;
              console.log(x, this.x); // outputs 1, 23
          }
      }
      o.m();

      示例中的兩個變量和屬性x都能被訪問,但它們被訪問的方式是截然不同,在log中訪問第一個x是通過作用域方式訪問了本地變量x,而this.x是通過執(zhí)行上下文方式訪問對象o的屬性x,因此輸出值也不盡相同。

      上下文問題

      接下來,我們修改一下前面的例子,在方法m()中添加一個函數(shù)f(),示例代碼如下:

      /**
       * Defines a literal object.
       * @type {Object}
       */
      var o = {
          x:23,
          m: function(){
              var x = 1;
              var f = function(){
                  console.log(x, this.x); // outputs 1, undefined
              }
              f();
          }
      }
      o.m();

      上面,我們通過調用方法m()來輸出x的值,由于方法m()的具體實現(xiàn)是通過調用函數(shù)f()來實現(xiàn)。

      當我們調用對象o的方法m()時,發(fā)現(xiàn)this.x是未定義的。

      這究竟是什么原因呢?回憶前面的例子,由于方法m()獲取了對象o的上下文,所以this是指向對象o的,難道是函數(shù)f()沒有獲取對象o的上下文,因此它不清楚this指向哪個對象?

      首先讓我們回顧一下函數(shù)和方法以及屬性和變量的區(qū)別:方法和對象關聯(lián),如:object.myMethod = function() {},而函數(shù)非對象關聯(lián):var myFunc = function {};同樣屬性也是對象關系的,如:object.myProperty = 23,而變量:var myProperty = 23。

      因為我們提到上下文是基于對象的,所以函數(shù)f()不能獲取對象o的執(zhí)行上下文。

      我們是否可以讓函數(shù)f()獲取對象o的執(zhí)行上下文呢?我們仔細地想一下,既然函數(shù)f()不清楚this指向的對象,那么可以直接調用對象的屬性就OK了。

      /**
       * Fixs broken context issue.
       * @type {Object}
       */
      var o = {
          x:23,
          m: function(){
              var x = 1;
              var f = function(){
                  console.log(x, o.x); // outputs 1, 23
              }
              f();
          }
      }
      o.m();

      我們在函數(shù)f()中直接調用對象o的屬性x,這樣函數(shù)f()就無需獲取執(zhí)行上下文直接調用對象的屬性了。

      現(xiàn)在,我們又遇到一個新的問題了,如果對象不是o而是p,那么我們就需要修改函數(shù)f()中的對象了,更嚴重的情況就是我們沒有辦法確定具體是哪個對象,示例代碼如下:

      /**
       * Defines a literal object.
       * @constructor
       */
      var C = function(){}
      C.prototype = {
          x:23,
          m: function(){
              var x = 1;
              var f = function(){
                  console.log(x, this.x); // outputs 1, undefined
              }
              f();
          }
      }
      var instance1 = new C();
      instance1.m();

      上下文實例問題

      上面,我們定義了函數(shù)C和它的原型對象,而且我們可以通過new方式創(chuàng)建C對象實例instance1,按照前面的方法解決Broken Context問題,具體實現(xiàn)如下:

      /**
       * Defines a literal object.
       * @constructor
       */
      var C = function(){}
      C.prototype = {
          x:23,
          m: function(){
              var x = 1;
              var f = function(){
                  console.log(x, instance1.x); // outputs 1, undefined
              }
              f();
          }
      }
      var instance1 = new C();
      instance1.m();

      如果我們在創(chuàng)建一個C的對象實例instance2,那么我們就不能指定函數(shù)f()中的對象了。

      其實,this是對象實例的抽象,當實例有多個甚至成千上百個的時候,我們需要通過this引用這些對象實例。

      因此,指定對象方法不能有效解決Broken Context問題,我們還是需要使用this來引用對象,前面我們講到由于函數(shù)f()沒有獲取對象o的執(zhí)行上下文,因此它不清楚this指向哪個對象,所以輸出this.x未定義,那么我們是否可以讓函數(shù)f()獲取對象的執(zhí)行上下文。

      跨作用域的上下文

      我們想想既然方法是基于對象的,而且可以獲取對象的執(zhí)行上下文,那么我們直接把f()定義為方法好了。

      現(xiàn)在,我們在C對象原型中定義方法f(),示例代碼如下:

      /**
       * Defines a literal object.
       * @constructor
       */
      var C = function(){}
      
      C.prototype = {
          x:10,
          m: function(){
              var x = 1;
              this.f();
          },
          f: function(){
              console.log(x, this.x); // Reference ERROR!!
          }
      }
      var instance1 = new C();
      instance1.m();

      好啦,我們在C對象原型中定義方法f(),那么方法f()就可以獲取對象的執(zhí)行上下文。

      現(xiàn)在,我們在Firefox運行以上代碼,結果輸出Reference ERROR,這究竟是什么原因呢?我們想了一下問題出于變量x中,由于方法f()不能獲取方法m()的作用域,所以變量x不在方法f()中。

      使用上下文解決作用域問題

      我們處于兩難的境地方法f()既要獲取執(zhí)行上下文,又要獲取方法m()的作用域;如果我們要獲取方法m()的作用域,那么我們需要把方法f()定義在m()中。

      接下來,我們把方法f()定義在m()中,具體實現(xiàn)如下:

      /**
       * Defines a literal object.
       * @constructor
       */
      var C = function(){}
      C.prototype = {
          x:23,
          m: function(){
              var x = 1;
              this.f = function(){
                  console.log(x, this.x); // outputs 1, 23
              }
              this.f();
          }
      }
      var instance1 = new C();
      instance1.m();

      現(xiàn)在我們通過this調用方法f(),它現(xiàn)在可以獲取對象instance1執(zhí)行上下文,并且也可以獲取方法m()的作用域,所以方法f()可以獲取屬性和變量x的值。

      使用作用域解決上下文問題

      接下來,繼續(xù)看一個例子,我們要在函數(shù)setTimeout()中調用方法onTimeout(),具體定義如下:

      /**
       * setTimeout function with Broken Context issue
       * @type {Object}
       */
      var o = {
          x:23,
          onTimeout: function(){
              console.log("x:", this.x);
          },
          m: function(){
              setTimeout(function(){
                  this.onTimeout(); // ERROR: this.onTimeout is not a function
              }, 1);
          }
      }
      o.m();

      同樣在函數(shù)setTimeout()中調用方法onTimeout()失敗,我們知道這是由于方法onTimeout()不能獲取對象執(zhí)行上下文。

      我們知道在方法m()中可以獲取對象執(zhí)行上下文,所以可以通過臨時變量引用this指向的對象,實例代碼如下:

      /**
       * Fixs setTimeout function with Broken Context issue.
       * @type {Object}
       */
      var o = {
          x:23,
          onTimeout: function(){
              console.log("x:", this.x); // outputs 23
          },
          m: function(){
              
              // Keeps instance reference.
              var self = this;
              setTimeout(function(){
                 // Gets m scrope. 
                  self.onTimeout();
              }, 1);
          }
      }
      o.m();

      上面,我們通過臨時變量self保存了this的引用,由于setTimeout()函數(shù)可以獲取m()的作用域,所用我們可以通過self. onTimeout()的方式調用onTimeout()方法。

      1.1.3 總結

      本博文通過介紹執(zhí)行上下文和作用域的異同、this的使用以及變量對象,讓我們加深對Javascript 語言特性的理解。

      首先,我們介紹了執(zhí)行上下文和this的的關系,并且執(zhí)行上下文是具有對象的;然后,介紹了作用域使變量在作用域范圍內可見,并且作用域是基于函數(shù)的。

      我們通過具體的例子介紹了在不同的作用域和執(zhí)行上下文中,對this和變量的影響加深了作用域和執(zhí)行上下文的理解,從而幫助我們更好的閱讀和編寫代碼。

      參考

      posted @ 2013-03-24 18:22  JK_Rush  閱讀(9958)  評論(5)    收藏  舉報
      主站蜘蛛池模板: 精品无码黑人又粗又大又长| 欧美成人va免费大片视频| 日韩欧国产美一区二区在线| 久热综合在线亚洲精品| 人妻体内射精一区二区三区| 亚洲日韩成人无码不卡网站| 亚洲国产精品午夜福利| 日本欧美大码aⅴ在线播放 | 毛葺葺老太做受视频| 中文字幕国产精品第一页| 中文字幕日韩精品一区二区三区| 国产精品一区二区三区蜜臀| 成人午夜在线观看日韩| 佛坪县| 自拍偷在线精品自拍偷99| 5D肉蒲团之性战奶水欧美| 金坛市| 亚洲精品久荜中文字幕 | 在线看av一区二区三区| 草草浮力影院| 免费无码AV一区二区波多野结衣| 在线人人车操人人看视频| 么公的好大好硬好深好爽视频| 亚洲av成人在线一区| 国内精品久久久久影院网站| 国产精品制服丝袜无码| 国产探花在线精品一区二区| 国产精品中文字幕第一页| 茶陵县| 亚洲国产成人精品女久久| 成人免费亚洲av在线| 国产精品VA尤物在线观看| 亚洲av激情一区二区三区| 国产精品无码不卡在线播放 | 久久天堂无码av网站| 国产日产亚洲系列最新| 青青草国产自产一区二区| 天堂亚洲免费视频| 国产尤物AV尤物在线看| 强奷漂亮雪白丰满少妇av| 国产精品青草久久久久福利99 |