" />
  • <center id="sm46c"></center>
  • <dfn id="sm46c"></dfn>
  • <strike id="sm46c"></strike>
  • <cite id="sm46c"><source id="sm46c"></source></cite>
    • <strike id="sm46c"><source id="sm46c"></source></strike>
      <option id="sm46c"></option>
      国产精品天天看天天狠,女高中生强奷系列在线播放,久久无码免费的a毛片大全,国产日韩综合av在线,亚洲国产中文综合专区在,特殊重囗味sm在线观看无码,中文字幕一区二区三区四区在线,无码任你躁久久久久久老妇蜜桃

      JavaScript必須掌握的基礎 ---> this

      2020-5-30    seo達人

      this

      this是我們在書寫代碼時最常用的關鍵詞之一,即使如此,它也是JavaScript最容易被最頭疼的關鍵詞。那么this到底是什么呢?


      如果你了解執行上下文,那么你就會知道,其實this是執行上下文對象的一個屬性:


      executionContext = {

         scopeChain:[ ... ],

         VO:{

             ...

         },

         this:  ?

      }

      執行上下文中有三個重要的屬性,作用域鏈(scopeChain)、變量對象(VO)和this。


      this是在進入執行上下文時確定的,也就是在函數執行時才確定,并且在運行期間不允許修改并且是永久不變的


      在全局代碼中的this

      在全局代碼中this 是不變的,this始終是全局對象本身。


      var a = 10;

      this.b = 20;

      window.c = 30;


      console.log(this.a);

      console.log(b);

      console.log(this.c);


      console.log(this === window) // true

      // 由于this就是全局對象window,所以上述 a ,b ,c 都相當于在全局對象上添加相應的屬性

      如果我們在代碼運行期嘗試修改this的值,就會拋出錯誤:


      this = { a : 1 } ; // Uncaught SyntaxError: Invalid left-hand side in assignment

      console.log(this === window) // true

      函數代碼中的this

      在函數代碼中使用this,才是令我們最容易困惑的,這里我們主要是對函數代碼中的this進行分析。


      我們在上面說過this的值是,進入當前執行上下文時確定的,也就是在函數執行時并且是執行前確定的。但是同一個函數,作用域中的this指向可能完全不同,但是不管怎樣,函數在運行時的this的指向是不變的,而且不能被賦值。


      function foo() {

         console.log(this);

      }


      foo();  // window

      var obj={

         a: 1,

         bar: foo,

      }

      obj.bar(); // obj

      函數中this的指向豐富的多,它可以是全局對象、當前對象、或者是任意對象,當然這取決于函數的調用方式。在JavaScript中函數的調用方式有一下幾種方式:作為函數調用、作為對象屬性調用、作為構造函數調用、使用apply或call調用。下面我們將按照這幾種調用方式一一討論this的含義。


      作為函數調用

      什么是作為函數調用:就是獨立的函數調用,不加任何修飾符。


      function foo(){

         console.log(this === window); // true

         this.a = 1;

         console.log(b); // 2

      }

      var b = 2;

      foo();

      console.log(a); // 1

      上述代碼中this綁定到了全局對象window。this.a相當于在全局對象上添加一個屬性 a 。


      在嚴格模式下,獨立函數調用,this的綁定不再是window,而是undefined。


      function foo() {

         "use strict";

         console.log(this===window); // false

         console.log(this===undefined); // true

      }

      foo();

      這里要注意,如果函數調用在嚴格模式下,而內部代碼執行在非嚴格模式下,this 還是會默認綁定為 window。


      function foo() {

         console.log(this===window); // true

      }



      (function() {

         "use strict";

         foo();

      })()

      對于在函數內部的函數獨立調用 this 又指向了誰呢?


      function foo() {

         function bar() {

             this.a=1;

             console.log(this===window); // true

         }

         bar()

      }

      foo();

      console.log(a); // 1

      上述代碼中,在函數內部的函數獨立調用,此時this還是被綁定到了window。


      總結:當函數作為獨立函數被調用時,內部this被默認綁定為(指向)全局對象window,但是在嚴格模式下會有區別,在嚴格模式下this被綁定為undefined。


      作為對象屬性調用

      var a=1;

      var obj={

         a: 2,

         foo: function() {

             console.log(this===obj); // true

             console.log(this.a); // 2

         }

      }

      obj.foo();

      上述代碼中 foo屬性的值為一個函數。這里稱 foo 為 對象obj 的方法。foo的調用方式為 對象 . 方法 調用。此時 this 被綁定到當前調用方法的對象。在這里為 obj 對象。


      再看一個例子:


      var a=1;

      var obj={

         a: 2,

         bar: {

             a: 3,

             foo: function() {

                 console.log(this===bar); // true

                 console.log(this.a); // 3

             }

         }

      }

      obj.bar.foo();

      遵循上面說的規則 對象 . 屬性 。這里的對象為 obj.bar 。此時 foo 內部this被綁定到了 obj.bar 。 因此 this.a 即為 obj.bar.a 。


      再來看一個例子:


      var a=1;

      var obj={

         a: 2,

         foo: function() {

             console.log(this===obj); // false

             console.log(this===window); // true

             console.log(this.a); // 1

         }

      }


      var baz=obj.foo;

      baz();

      這里 foo 函數雖然作為對象obj 的方法。但是它被賦值給變量 baz 。當baz調用時,相當于 foo 函數獨立調用,因此內部 this被綁定到 window。


      使用apply或call調用

      apply和call為函數原型上的方法。它可以更改函數內部this的指向。


      var a=1;

      function foo() {

         console.log(this.a);

      }

      var obj1={

         a: 2

      }

      var obj2={

         a: 3

      }

      var obj3={

         a: 4

      }

      var bar=foo.bind(obj1);

      bar();// 2  this => obj1

      foo(); // 1  this => window

      foo.call(obj2); // 3  this => obj2

      foo.call(obj3); // 4  this => obj3

      當函數foo 作為獨立函數調用時,this被綁定到了全局對象window,當使用bind、call或者apply方法調用時,this 被分別綁定到了不同的對象。


      作為構造函數調用

      var a=1;

      function Person() {

         this.a=2;  // this => p;

      }

      var p=new Person();

      console.log(p.a); // 2

      上述代碼中,構造函數 Person 內部的 this 被綁定為 Person的一個實例。


      總結:


      當我們要判斷當前函數內部的this綁定,可以依照下面的原則:


      函數是否在是通過 new 操作符調用?如果是,this 綁定為新創建的對象

      var bar = new foo();     // this => bar;

      函數是否通過call或者apply調用?如果是,this 綁定為指定的對象

      foo.call(obj1);  // this => obj1;

      foo.apply(obj2);  // this => obj2;

      函數是否通過 對象 . 方法調用?如果是,this 綁定為當前對象

      obj.foo(); // this => obj;

      函數是否獨立調用?如果是,this 綁定為全局對象。

      foo(); // this => window

      DOM事件處理函數中的this

      1). 事件綁定


      <button id="btn">點擊我</button>


      // 事件綁定


      function handleClick(e) {

         console.log(this); // <button id="btn">點擊我</button>

      }

             document.getElementById('btn').addEventListener('click',handleClick,false);  //   <button id="btn">點擊我</button>

             

      document.getElementById('btn').onclick= handleClick; //  <button id="btn">點擊我</button>

      根據上述代碼我們可以得出:當通過事件綁定來給DOM元素添加事件,事件將被綁定為當前DOM對象。


      2).內聯事件


      <button onclick="handleClick()" id="btn1">點擊我</button>

      <button onclick="console.log(this)" id="btn2">點擊我</button>


      function handleClick(e) {

         console.log(this); // window

      }


      //第二個 button 打印的是   <button id="btn">點擊我</button>

      我認為內聯事件可以這樣理解:


      //偽代碼


      <button onclick=function(){  handleClick() } id="btn1">點擊我</button>

      <button onclick=function() { console.log(this) } id="btn2">點擊我</button>

      這樣我們就能理解上述代碼中為什么內聯事件一個指向window,一個指向當前DOM元素。(當然瀏覽器處理內聯事件時并不是這樣的)


      定時器中的this

      定時器中的 this 指向哪里呢?


      function foo() {

         setTimeout(function() {

             console.log(this); // window

         },1000)

      }

      foo();  

      再來看一個例子


      var name="chen";

      var obj={

         name: "erdong",

         foo: function() {

             console.log(this.name); // erdong

             setTimeout(function() {

                 console.log(this.name); // chen

             },1000)

         }

      }

      obj.foo();

      到這里我們可以看到,函數 foo 內部this指向為調用它的對象,即:obj 。定時器中的this指向為 window。那么有什么辦法讓定時器中的this跟包裹它的函數綁定為同一個對象呢?


      1). 利用閉包:


      var name="chen";

      var obj={

         name: "erdong",

         foo: function() {

             console.log(this.name) // erdong

             var that=this;

             setTimeout(function() {

                 // that => obj

                 console.log(that.name); // erdong

             },1000)

         }

      }

      obj.foo();

      利用閉包的特性,函數內部的函數可以訪問含義訪問當前詞法作用域中的變量,此時定時器中的 that 即為包裹它的函數中的 this 綁定的對象。在下面我們會介紹利用 ES6的箭頭函數實現這一功能。


      當然這里也可以適用bind來實現:


      var name="chen";

      var obj={

         name: "erdong",

         foo: function() {

             console.log(this.name); // erdong

             setTimeout(function() {

                 // this => obj

                 console.log(this.name); // erdong

             }.bind(this),1000)

         }

      }

      obj.foo();

      被忽略的this

      如果你把 null 或者 undefined 作為 this 的綁定對象傳入 call 、apply或者bind,這些值在調用時會被忽略,實例 this 被綁定為對應上述規則。


      var a=1;

      function foo() {

         console.log(this.a); // 1  this => window

      }

      var obj={

         a: 2

      }

      foo.call(null);

      var a=1;

      function foo() {

         console.log(this.a); // 1  this => window

      }

      var obj={

         a: 2

      }

      foo.apply(null);

      var a=1;

      function foo() {

         console.log(this.a); // 1  this => window

      }

      var obj={

         a: 2

      }

      var bar = foo.bind(null);

      bar();

      bind 也可以實現函數柯里化:


      function foo(a,b) {

         console.log(a,b); // 2  3

      }

      var bar=foo.bind(null,2);

      bar(3);

      更復雜的例子:


      var foo={

         bar: function() {

             console.log(this);

         }

      };


      foo.bar(); // foo

      (foo.bar)(); // foo


      (foo.bar=foo.bar)(); // window

      (false||foo.bar)();  // window

      (foo.bar,foo.bar)();  // window

      上述代碼中:


      foo.bar()為對象的方法調用,因此 this 綁定為 foo 對象。


      (foo.bar)() 前一個() 中的內容不計算,因此還是 foo.bar()


      (foo.bar=foo.bar)() 前一個 () 中的內容計算后為 function() { console.log(this); } 所以這里為匿名函數自執行,因此 this 綁定為 全局對象 window


      后面兩個實例同上。


      這樣理解會比較好:


      (foo.bar=foo.bar)  括號中的表達式執行為 先計算,再賦值,再返回值。

      (false||foo.bar)()    括號中的表達式執行為 判斷前者是否為 true ,若為true,不計算后者,若為false,計算后者并返回后者的值。

      (foo.bar,foo.bar)   括號中的表達式之行為分別計算 “,” 操作符兩邊,然后返回  “,” 操作符后面的值。

      箭頭函數中的this

      箭頭函數時ES6新增的語法。


      有兩個作用:


      更簡潔的函數

      本身不綁定this

      代碼格式為:


      // 普通函數

      function foo(a){

         // ......

      }

      //箭頭函數

      var foo = a => {

         // ......

      }


      //如果沒有參數或者參數為多個


      var foo = (a,b,c,d) => {

         // ......

      }

      我們在使用普通函數之前對于函數的this綁定,需要根據這個函數如何被調用來確定其內部this的綁定對象。而且常常因為調用鏈的數量或者是找不到其真正的調用者對 this 的指向模糊不清。在箭頭函數出現后其內部的 this 指向不需要再依靠調用的方式來確定。


      箭頭函數有幾個特點(與普通函數的區別)


      箭頭函數不綁定 this 。它只會從作用域鏈的上一層繼承 this。

      箭頭函數不綁定arguments,使用reset參數來獲取實參的數量。

      箭頭函數是匿名函數,不能作為構造函數。

      箭頭函數沒有prototype屬性。

      不能使用 yield 關鍵字,因此箭頭函數不能作為函數生成器。

      這里我們只討論箭頭函數中的this綁定。


      用一個例子來對比普通函數與箭頭函數中的this綁定:


      var obj={

         foo: function() {

             console.log(this); // obj

         },

         bar: () => {

             console.log(this); // window

         }

      }

      obj.foo();

      obj.bar();

      上述代碼中,同樣是通過對象 . 方法調用一個函數,但是函數內部this綁定確是不同,只因一個數普通函數一個是箭頭函數。


      用一句話來總結箭頭函數中的this綁定:


      個人上面說的它會從作用域鏈的上一層繼承 this ,說法并不是很正確。作用域中存放的是這個函數當前執行上下文與所有父級執行上下文的變量對象的集合。因此在作用域鏈中并不存在 this 。應該說是作用域鏈上一層對應的執行上下文中繼承 this 。


      箭頭函數中的this繼承于作用域鏈上一層對應的執行上下文中的this


      var obj={

         foo: function() {

             console.log(this); // obj

         },

         bar: () => {

             console.log(this); // window

         }

      }

      obj.bar();

      上述代碼中obj.bar執行時的作用域鏈為:


      scopeChain = [

         obj.bar.AO,

         global.VO

      ]

      根據上面的規則,此時bar函數中的this指向為全局執行上下文中的this,即:window。


      再來看一個例子:


      var obj={

         foo: function() {

             console.log(this); // obj

             var bar=() => {

                 console.log(this); // obj

             }

             bar();

         }

      }

      obj.foo();

      在普通函數中,bar 執行時內部this被綁定為全局對象,因為它是作為獨立函數調用。但是在箭頭函數中呢,它卻綁定為 obj 。跟父級函數中的 this 綁定為同一對象。


      此時它的作用域鏈為:


      scopeChain = [

          bar.AO,

          obj.foo.AO,

          global.VO

      ]

      這個時候我們就差不多知道了箭頭函數中的this綁定。


      繼續看例子:


      var obj={

         foo: () => {

             console.log(this); // window

             var bar=() => {

                 console.log(this); // window

             }

             bar();

         }

      }

      obj.foo();

      這個時候怎么又指向了window了呢?


      我們還看當 bar 執行時的作用域鏈:


      scopeChain = [

          bar.AO,

          obj.foo.AO,

          global.VO

      ]

      當我們找bar函數中的this綁定時,就會去找foo函數中的this綁定。因為它是繼承于它的。這時 foo 函數也是箭頭函數,此時foo中的this綁定為window而不是調用它的obj對象。因此 bar函數中的this綁定也為全局對象window。


      我們在回頭看上面關于定時器中的this的例子:


      var name="chen";

      var obj={

         name: "erdong",

         foo: function() {

             console.log(this.name); // erdong

             setTimeout(function() {

                 console.log(this); // chen

             },1000)

         }

      }

      obj.foo();

      這時我們就可以很簡單的讓定時器中的this與foo中的this綁定為同一對象:


      var name="chen";

      var obj={

         name: "erdong",

         foo: function() {

             // this => obj

             console.log(this.name); // erdong

             setTimeout(() =>  {

                 // this => foo中的this => obj

                 console.log(this.name); // erdong

             },1000)

         }

      }

      obj.foo();

      日歷

      鏈接

      個人資料

      藍藍設計的小編 http://www.li-bodun.cn

      存檔

      主站蜘蛛池模板: 99久久99久久加热有精品| 无码激情亚洲一区| 亚洲日产精品一二三四区| 亚洲色五月| 国产精品亚洲аv无码播放| 精品国产一区二区三区www| 噜噜噜噜私人影院| 免费无码精品黄av电影| 人人爽久久涩噜噜噜av| 亚洲精品久久久久久久久av无码 | 国产亚洲视频免费播放| 国精品无码一区二区三区左线| 直接黄91麻豆网站| 偷偷做久久久久网站| 日韩av在线毛片| 久久久久欧美精品| 六枝特区| 亚洲国产精品一二三区| 午夜国产理论大片高清| 中文字幕伦视频| 亚洲国产精品一区二区成人片| 黔西县| 91福利视频一区二区| 秋霞国产在线| 国产在线精品中文字幕| 91精品国产自产在线蜜臀| 国产成人拍精品视频午夜网站 | 午夜亚洲乱码伦小说区69堂| 性色av一区二区三区精品| 一本大道大臿蕉视频无码| 梁河县| 亚洲最大综合久久网成人| 国产精品久久无码不卡黑寡妇| 一本大道东京热无码aⅴ| 久久精品久久久久久噜噜| 视频二区国产精品职场同事| 国产精品99久久久久久猫咪| 精品视频一区二区三区在线播| 看免费的无码区特aa毛片| 亚洲午夜18| 久久中文字幕一区二区|