<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 this 的一些學習總結

      1.1.1 摘要

      相信有C++、C#或Java等編程經驗的各位,對于this關鍵字再熟悉不過了。由于Javascript是一種面向對象的編程語言,它和C++、C#或Java一樣都包含this關鍵字,接下來我們將向大家介紹Javascript中的this關鍵字。

      本文目錄

      1.1.2 正文

       

      由于許多面向對象的編程語言都包含this關鍵字,我們會很自然地把this和面向對象的編程方式聯系在一起,this通常指向利用構造器新創建出來的對象。而在ECMAScript中,this不僅僅只用來表示創建出來的對象,也是執行上下文的一個屬性:

      activeExecutionContext = {
        // Variable object.
        VO: {...},
        this: thisValue
      };

      全局代碼中的this

      // Global scope
      // The implicit property of 
      // the global object
      foo1 = "abc";
      alert(foo1); // abc
       
      // The explicit property of 
      // the global object
      this.foo2 = "def";
      alert(foo2); // def
      
      // The implicit property of 
      // the global object
      var foo3 = "ijk";
      alert(foo3); // ijk

      前面我們通過顯式和隱式定義了全局屬性foo1、foo2和foo3,由于this在全局上下文中,所以它的值是全局對象本身(在瀏覽器中是window object);接下來我們將介紹函數中的this

      函數中的this

      this在函數代碼中,情況就復雜多了,并且會引發很多的問題。

      函數代碼中this值的第一個特性(同時也是最主要的特性)就是:它并非靜態的綁定在函數上

      正如此前提到的,this的值是在進入執行上下文(Excution context)的階段確定的,并且在函數代碼中的話,其值每次都不盡相同。

      然而,一旦進入執行代碼階段,其值就不能改變了。如果要想給this賦一個新的值是不可能的,因為在那時this根本就不是變量了。

      接下來,我們通過具體的例子說明函數中的this

      首先我們定義兩個對象foo和person,foo包含一個屬性name,而person包含屬性name和方法say(),具體的定義如下:

      // Defines foo object.
      var foo = {
          name: "Foo"
      };
      
      // Defines person object.
      var person = {
          name: "JK_Rush",
          say: function() {
              alert(this === person);
              alert("My name is " + this.name);
          }
      };
      
      person.say();  // My name is JK_Rush
      
      // foo and person object refer to 
      // the same function say
      foo.say = person.say;
      
      foo.say();    // My name is Foo.

      通過上面的代碼,我們發現調用person的say()方法時,this指向person對象,當通過賦值方式使得foo的say()方法指向peson中的say()方法時。我們調用foo的say()方法,發現this不是指向person對象,而不是指向foo對象,這究竟是什么原因呢?

      首先,我們必須知道this的值在函數中是非靜態的,它的值確定在函數調用時,具體代碼執行前,this的值是由激活上下文代碼的調用者決定的,比如說,調用函數的外層上下文;更重要的是,this的值是由調用表達式的形式決定的,所以說this并非靜態的綁定在函數上

      由于this并非靜態地綁定在函數上,那么我們是否可以在函數中動態地修改this的值呢?

      // Defines foo object.
      var foo = {
          name: "Foo"
      };
      
      // Defines person object.
      var person = {
          name: "JK_Rush",
          say: function() {
              alert(this === person);
              this = foo;  // ReferenceError
              alert("My name is " + this.name);
          }
      };
      
      person.say();  // My name is JK_Rush
      

      現在我們在方法say()中,動態地修改this的值,當我們重新執行以上代碼,發現this的值引用錯誤。這是由于一旦進入執行代碼階段(函數調用時,具體代碼執行前),this的值就確定了,所以不能改變了。

      引用類型

      前面我們提到this的值是由激活上下文代碼的調用者決定的,更重要的是,this的值是由調用表達式的形式決定的;那么表達式的形式是如何影響this的值呢?

      首先,讓我們介紹一個內部類型——引用類型,它的值可以用偽代碼表示為一個擁有兩個屬性的對象分別是:base屬性(屬性所屬的對象)以及該base對象中的propertyName屬性:

      // Reference type.
      var valueOfReferenceType = {
        base: mybase,
        propertyName : 'mybasepropertyName' 
      };

      引用類型的值只有可能是以下兩種情況:

      • 當處理一個標識符的時候
      • 或者進行屬性訪問的時候

      標識符其實就是變量名函數名函數參數名以及全局對象的未受限的屬性

      // Declares varible.
      var foo = 23;
      
      // Declares a function
      function say() {
          // Your code.
      }

      中間過程中,對應的引用類型如下:

      // Reference type.
      var fooReference = {
        base: global,
        propertyName: 'foo'
      };
       
      var sayReference = {
        base: global,
        propertyName: 'say'
      };

      我們知道Javascript中屬性訪問有兩種方式:點符號和中括號符號:

      // Invokes the say method.
      foo.say();
      foo['say']();

      由于say()方法是標識符,所以它對應于foo對象引用類型如下:

      // Reference type.
      var fooSayReference = {
        base: foo,
        propertyName: 'say'
      };

      我們發現say()方法的base屬性值為foo對象,那么它對應的this屬性也將指向foo對象。

      假設,我們直接調用say()方法,它對應的引用類型如下:

      // Reference type.
      var sayReference = {
        base: global,
        propertyName: 'say'
      };

      由于say()方法的base屬性值為global(通常來說是window object),那么它對應的this屬性也將指向global。

      函數上下文中this的值是函數調用者提供并且由當前調用表達式的形式而定的。如果在調用括號()的左邊有引用類型的值,那么this的值就會設置為該引用類型值的base對象。 所有其他情況下(非引用類型),this的值總是null。然而,由于null對于this來說沒有任何意義,因此會隱式轉換為全局對象。

      函數調用以及非引用類型

      前面我們提到,當調用括號左側為非引用類型的時,this的值會設置為null,并最終隱式轉換為全局對象。

      現在我們定義了一個匿名自執行函數,具體實現如下:

      // Declares anonymous function
      (function () {
        alert(this); // null => global
      })();

      由于括號()左邊的匿名函數是非引用類型對象(它既不是標識符也不屬于屬性訪問),因此,this的值設置為全局對象。

      // Declares object.
      var foo = {
        bar: function () {
          alert(this);
        }
      };
       
      (foo.bar)();          // foo.
      (foo.bar = foo.bar)(); // global?
      (false || foo.bar)();  // global?
      (foo.bar, foo.bar)();  // global

      這里注意到四個表達式中,只有第一個表達式this是指向foo對象的,而其他三個表達式則執行global。

      現在我們又有疑問了:為什么屬性訪問,但是最終this的值不是引用類型對象而是全局對象呢?

      我們注意到表達式二是賦值(assignment operator),與表達式一組操作符不同的是,它會觸發調用GetValue方法(參見11.13.1中的第三步)。 最后返回的時候就是一個函數對象了(而不是引用類型的值了),這就意味著this的值會設置為null,最終會變成全局對象。

      第三和第四種情況也是類似的——逗號操作符和OR邏輯表達式都會觸發調用GetValue方法,于是相應地就會丟失原先的引用類型值,變成了函數類型,this的值就變成了全局對象了。

      引用類型以及this的null值

      對于前面提及的情形,還有例外的情況,當調用表達式左側是引用類型的值,但是this的值卻是null,最終變為全局對象(global object)。 發生這種情況的條件是當引用類型值的base對象恰好為活躍對象(activation object)。

      當內部子函數在父函數中被調用的時候就會發生這種情況,通過下面的示意代碼介紹活躍對象:

      // Declares foo function.
      function foo() {
        function bar() {
          alert(this); // global
        }
        // The same as AO.bar().  
        bar();
      }

      由于活躍對象(activation object)總是會返回this值為——null(用偽代碼來表示AO.bar()就相當于null.bar()),然后,this的值最終會由null轉變為全局對象。

      當函數調用包含在with語句的代碼塊中,并且with對象包含一個函數屬性的時候,就會出現例外的情況。with語句會將該對象添加到作用域鏈的最前面,在活躍對象的之前。 相應地,在引用類型的值(標識符或者屬性訪問)的情況下,base對象就不再是活躍對象了,而是with語句的對象。另外,值得一提的是,它不僅僅只針對內部函數,全局函數也是如此, 原因就是with對象掩蓋了作用域鏈中更高層的對象(全局對象或者活躍對象):

      函數作為構造器被調用時this的值

      函數作為構造函數時,我們通過new操作符創建實例對象是,它會調用Foo()函數的內部[[Construct]]方法;在對象創建之后,會調用內部的[[Call]]方法,然后所有Foo()函數中this的值會設置為新創建的對象。

      // Declares constructor
      function Foo() {
        // The new object.
        alert(this);
        this.x = 10;
      }
       
      var foo = new Foo();
      foo.x = 23;
      alert(foo.x); // 23

      手動設置函數調用時this的值

      Function.prototype原型上定義了兩個方法,允許手動指定函數調用時this的值。這兩個方法分別是:.apply()和.call()。這兩個方法都接受第一個參數作為調用上下文中this的值,而這兩個方法的區別是傳遞的參數,對于.apply()方法來說,第二個參數接受數組類型(或者是類數組的對象,比如arguments), 而.call()方法接受任意多的參數(通過逗號分隔);這兩個方法只有第一個參數是必要的——this的值。

      通過示例代碼介紹call()方法和apply()方法的使用:

      var myObject = {};
       
      var myFunction = function(param1, param2) {
          
        //setviacall()'this'points to my Object when function is invoked
        this.foo = param1;
        this.bar = param2;
          
        //logs Object{foo = 'foo', bar = 'bar'}
        console.log(this); 
      };
       
      // invokes function, set this value to myObject
      myFunction.call(myObject, 'foo', 'bar'); 
      
      // logs Object {foo = 'foo', bar = 'bar'}
      console.log(myObject);

      call()方法第一個參數是必要的this值,接著我們可以傳遞任意多個參數,接著介紹apply()方法的使用。

      var myObject = {};
       
      var myFunction = function(param1, param2) {
          
        //set via apply(), this points to my Object when function is invoked
        this.foo=param1;
        this.bar=param2;
          
        // logs Object{foo='foo', bar='bar'}  
        console.log(this); 
      };
       
      // invoke function, set this value
      myFunction.apply(myObject, ['foo', 'bar']); 
      
      // logs Object {foo = 'foo', bar = 'bar'}
      console.log(myObject); 

      通過與call()方法對比,我們發現apply()方法和call()方法沒有太大的區別,只是方法簽名不一樣。

      1.1.3 總結

      本文介紹Javascript中this的使用,更重要的是幫助我們能更好地理解this值在全局、函數、構造函數以及一些特例的情況中值的變化。

      對于在函數上下文中this的值是函數調用者提供并且由當前調用表達式的形式而定的。如果在調用括號()的左邊有引用類型的值,那么this的值就會設置為該引用類型值的base對象。 所有其他情況下(非引用類型),this的值總是null。然而,由于null對于this來說沒有任何意義,因此會隱式轉換為全局對象。

      對于特例情況,我們要記住賦值符、逗號操作符以及||邏輯表達式,會使this丟失原先的引用類型值,變成了函數類型,this的值就變成了全局對象了

      參考

      [1] http://dmitrysoshnikov.com/ecmascript/chapter-3-this/ 英文版

      [2] http://blog.goddyzhao.me/post/11218727474/this       譯文

      [3] https://net.tutsplus.com/tutorials/javascript-ajax/fully-understanding-the-this-keyword/

      posted @ 2012-07-31 21:39  JK_Rush  閱讀(6814)  評論(18)    收藏  舉報
      主站蜘蛛池模板: 深夜福利资源在线观看| 亚洲欧美日韩成人综合一区| 亚洲精品一二三中文字幕| 婷婷综合久久狠狠色成人网| 亚洲一区二区偷拍精品| 欧洲美熟女乱又伦免费视频| 丹巴县| 蜜桃视频网站| 亚洲日本中文字幕乱码中文| 午夜高清福利在线观看| 东方av四虎在线观看| 亚洲av熟女国产一二三| 国产亚洲精品在天天在线麻豆| 女人张开腿让男人桶爽| 亚洲深深色噜噜狠狠网站| 欧美刺激性大交| 在线涩涩免费观看国产精品| 新蔡县| 老色鬼永久精品网站| 久久久www成人免费精品| 亚洲深夜精品在线观看| 91精品乱码一区二区三区| 香港经典a毛片免费观看播放| 狠狠色噜噜狠狠狠888米奇视频| 加勒比亚洲视频在线播放| 成人网站免费在线观看| 亚洲欧美日韩成人综合一区| gogo无码大胆啪啪艺术| 国产成人精品久久性色av| 在线精品自拍亚洲第一区| 亚洲深深色噜噜狠狠网站| 高清中文字幕一区二区| 少妇高潮水多太爽了动态图| 白丝乳交内射一二三区| 国产AV巨作丝袜秘书| 国产在线精品中文字幕| 新和县| 日本伊人色综合网| 9久久伊人精品综合| 亚洲春色在线视频| 在线播放免费人成毛片|