亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

Javascript中神奇的this

2019-11-20 10:45:30
字體:
來源:轉載
供稿:網友

Javascript 當中的 this 與其他語言是完全不同的機制,很有可能會讓一些編寫其他語言的工程師迷惑。

1. 誤以為 this 指向函數自身

根據 this 的英語語法,很容易將函數中出現的 this 理解為函數自身。在 javascript 當中函數作為一等公民,確實可以在調用的時候將屬性值存儲起來。但是如果使用方法不對,就會發生與實際預期不一致的情況。具體情況,請看下面代碼

  function fn(num){    this.count++;  }    fn.count = 0;    for(var i=0;i<3;i++){    fn(i);  }  console.log(fn.count); // 0

如果 fn 函數里面的 this 指向自身函數,那么 count 屬性的屬性值就應該產生變化,但實際上卻是紋絲不動。對于這個問題,有些人會利用作用域來解決,比如這么寫

  var data = {    count:0  };    function fn(num){    data.count++;  }    for(var i=0;i<3;i++){    fn(i);  }    console.log(data.count);  //3

又或者更直接的這么寫

  function fn(num){    fn.count++;  }    fn.count = 0;    for(var i=0;i<3;i++){    fn(i);  }    console.log(fn.count);//3

雖然這兩種方式都輸出了正確的結果,但是卻避開了 this 到底綁定在哪里的問題。如果對一個事物的工作原理不清晰,就往往會產生頭痛治頭,腳痛治腳的問題,從而導致代碼變得的丑陋,而且維護性也會變得很差。

2. this神奇的綁定規則

2.1 默認綁定規則

第一種是最常見的 this 的綁定,看一下下面的代碼

  function fn(){    console.log(window === this); //瀏覽器環境  }  fn(); //true

函數fn 是直接在全局作用域下調用的,沒有帶其他任何修飾,這種情況下,函數調用的時候使用了 this 的默認綁定,指向了全局對象。

這樣就清楚了第一個例子中的 this 指向, fn 函數中的 this 指向了全局變量,所以 this.count++ 相當于 window.count++(瀏覽器環境下),當然不會對 fn 函數的count屬性產生影響。

有一點要說明的是,上面種情況只能在非嚴格模式(strict mode)下才能發生,在嚴格模式下,會將 this 默認綁定為 undefined。以避免全局變量的污染。

2.2 隱式綁定規則

如果函數在以對象為上下文進行調用,那么 this 的綁定就會產生變化。this 會綁定到調用這個函數的對象,查看下面代碼:

  var obj = {    a:1,    fn:function(){      console.log(this.a);    }  }    obj.fn(); //1

即使函數聲明不在對象當中,this 指向仍會產生變化

  function fn(){    console.log(this.a);  }  var obj = {    a:1,    fn:fn  }  obj.fn(); //1

由此可見,this 的綁定,不與函數定義的位置有關,而是與調用者和調用方式有關。

在隱式的綁定規則下,有一些特殊的地方,需要注意。

2.2.1 多層對象調用 this 的指向

  function fn(){    console.log(this.a);  }  var obj = {    a:1,    obj2:obj2  }  var obj2 = {    a:2,    obj3:obj3  }  var obj3 = {    a:3,    fn:fn  }    obj.obj2.obj3.fn(); //3

在多層對象引用下,this 指向的是調用的函數的那個對象。

2.2.2 隱式賦值可能存在丟失現象

查看下面代碼

  function fn(){    console.log(this);  }  var  obj = {    fn:fn  }    var fun = obj.fn;  fun(); //window

雖然 fn 引用了 obj.fun ,但是函數的調用方式,仍是不帶任何修飾的,所以 this 還是綁定在了 window 上。
還有一種情況,容易讓大家忽略,那就是傳參的時候,其實會進行隱式賦值。

 function fn(){    console.log(this);  }    function doFn(fn){    fn();  }    var obj = {    fn:fn  }    doFn(obj.fn); //window

隱式綁定 this 不是一種很推薦的方式,因為很有可能就發生丟失的情況,如果業務當中對 this 的綁定有要求,建議還是使用顯示綁定的方式。

2.3 顯式綁定規則

顯示綁定就是利用函數原型上的 apply 與 call 方法來對 this 進行綁定。用法就是把想要綁定的對象作為第一個參數傳進去。

  function fn(){    console.log(this);  }    var obj = {};    fn.call(obj); //{}    

有些時候會想將函數的 this 綁定在某個對象上,但是不需要立即調用,這樣的話,直接利用 call 或者 apply 是無法做的。

  function fn(){    console.log(this);  }    function bind(fn){    fn();  }    var obj = {    fn:fn  }    bind.call(obj,fn); //window

上面這個例子,看似好像可以,但實際上是 bind 函數的 this 綁定到了 obj 這個對象,但是 fn 仍然是沒有任何修飾的調用,所以 fn 仍然是默認的綁定方式。

  function fn(){    console.log(this);  }    function bind(fn,obj){    return function(){      fn.apply(obj,arguments);    }  }    var obj = {    fn:fn  }    var fun = bind(fn,obj);  fun(); //obj

這樣調用,就可以將靈活多變的 this ,牢牢的控制住了,因為 fn 的調用方式為 apply 調用。所以,this 就被綁定在傳入的 obj 對象上,在 ES5 當中,函數的原型方法上多了一個 bind。效果與上面的函數基本一致,具體用法限于篇幅就不多說了。

2.4 new 綁定

new 是一個被很多人誤解的一個關鍵字,但實際上 javascript 的 new 與傳統面向對象的語言完全不同。
個人把 new 理解為一種特殊的函數調用,當使用 new 關鍵字來調用函數的時候,會執行下面操作,

  • 創建一個全新的對象
  • 將空對象的 __proto__ 指向構造函數的 prototype
  • 將新對象的 this 綁定到調用的函數上
  • 如果函數返回值為基本類型或者為 this又或者不返回任何值,那么將會返回這個創建的新對象,如果返回了一個對象,那么則會返回這個對象,而不會返回創建的新對象。
  function fn(a){    this.a = a;  }  fn.prototype.hi = function(){    console.log('hi')  }    var obj = new fn(2);    console.log(obj);  function fn(a){    this.a = a;    return {};  }    var obj = new fn(2);    console.log(obj); //{}

2.5 特殊的傳參

null 和 undefined 也是可以作為 this 的綁定對象的,但是實際上應用的是默認的綁定。
但是這種傳參的實際效用是什么呢?
常見的用法是將一個數組展開,作為參數傳入參數。比如

  function fn(a,b){    console.log('a:',a,'b:',b);  }    fn.apply(null,[1,2]); // a: 1 b: 2

但是這種用法會有一個坑,那就是如果函數存在了 this ,那么就會應用默認的綁定規則,將 this 綁定在全局對象上,發生于預期不一致的情況。為了代碼更加穩健,可以使創建一個比空對象更空的對象。

var obj = Object.create(null);console.log(obj.__proto__); //undefinedvar obj2 = {}console.log(obj2.__proto__); //Object {}

Object原型上有一個 create 方法,這個方法會創建一個對象,然后將對象的原型指向傳入的參數,所以傳入 null 的話,產生一個沒有 prototype 的對象,所以會比空對象更加"空"。

所以傳入這個對象,會比傳入 null 更加安全。

var obj = Object.create(null);fn.apply(obj,[1,2]);

2.6 根據作用域來決定 this 的綁定

在 ES6 當中,出現了一個新的函數類型,箭頭函數。

如果使用箭頭函數,那么就不會使用上面提到的四種 this 綁定方式,而是根據作用域來決定

比較常見的是用于事件函數和定時器的情況。

下面是比較常見的傳統 this 寫法

  function fn(){    var _this = this;    setTimeout(function(){      console.log(_this.a);    },100)  }  var obj = {    a:2  }    fn.call(obj); //2  

如果使用箭頭函數則可以這么寫

  function fn(){    setTimeout(()=>{      //this 來源于 fn 函數的作用域      console.log(this.a);    },100)  }  var obj = {    a:2  }    fn.call(obj); //2

2.7 事件函數當中 this 的綁定機制

如果是在事件函數當中,this 的綁定是指向觸發事件的 DOM 元素的,

$('body')[0].addEventListener('click',function(){  console.log(this);},false);

點擊 body 元素之后,控制臺則會顯示 body 元素

3. 小結

如果想判斷一個函數的 this 綁定在哪里,首先是找到函數的調用位置,之后是按照規則來判斷。

  • 如果函數調用時沒有任何修飾條件,那么在嚴格模式下則會綁定到 undefined ,非嚴格模式下會綁定到全局。
  • 如果是用對象做上下文,來對函數進行調用,那么則會綁定到調用的這個對象上。
  • 如果是用 call 或者 apply 方法來進行調用的,則會綁定到第一個傳入參數上。
  • 如果是使用 new 關鍵字來調用函數的,則會綁定到新創建的那個對象上.
  • 如果是在事件函數內,則會綁定到觸發事件的那個DOM元素上。

以上就是關于Javascript中神奇的this的相關介紹,希望對大家的學習有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
伊人亚洲福利一区二区三区| 国产成人aa精品一区在线播放| 欧美激情18p| 精品国产一区二区三区久久狼黑人| 欧美激情2020午夜免费观看| 亚洲午夜av电影| 日韩视频免费大全中文字幕| 亚洲天堂成人在线| 九九热最新视频//这里只有精品| 精品国产91久久久久久| 亚洲精品在线91| 日韩在线播放av| 欧美激情18p| 日韩电影免费观看在线观看| 亚洲国产精品成人av| 日韩av资源在线播放| 亚洲区一区二区| 久久精品精品电影网| 日韩av在线免费看| 亚洲欧美成人在线| 欧美与黑人午夜性猛交久久久| 国产一区二区三区日韩欧美| 91精品久久久久久久久久| 亚洲激情在线观看| 亚洲欧美日本另类| 国产精品久久久久久久久久久久| 国产婷婷色综合av蜜臀av| 精品视频一区在线视频| 97视频免费在线看| 亚洲综合色激情五月| 亚洲色图国产精品| 久久视频国产精品免费视频在线| 成人xvideos免费视频| 97在线视频精品| 68精品国产免费久久久久久婷婷| 亚洲欧美日韩国产精品| 亚洲视频在线免费观看| 欧美日韩在线视频首页| 欧美性极品xxxx娇小| 亚洲福利视频专区| 精品国产一区二区三区在线观看| 日韩中文字幕不卡视频| 久久久人成影片一区二区三区| 亚洲天堂网站在线观看视频| 亚洲激情在线观看| 欧美午夜激情小视频| 欧美中文在线视频| 久久夜色精品国产欧美乱| 亚洲一区二区三| 亚洲欧美国内爽妇网| 亚洲精品丝袜日韩| 91精品国产91久久久久久吃药| 亚洲美女久久久| 在线不卡国产精品| 日韩的一区二区| 欧美中文字幕在线播放| 夜夜嗨av色一区二区不卡| 亚洲欧美在线第一页| 久久精品中文字幕一区| 日韩在线中文字| 成人激情免费在线| 色综合久久悠悠| 国产91色在线播放| 亚洲国产中文字幕在线观看| 国产美女久久久| 日韩av影院在线观看| 91欧美精品成人综合在线观看| 成人免费网视频| 欧美亚洲日本网站| 欧美自拍视频在线观看| 九九热精品视频在线播放| 国产精品777| 高跟丝袜欧美一区| 欧美日韩一区二区免费视频| 国产精品日韩在线一区| 亚洲国产成人爱av在线播放| 青青草成人在线| 在线不卡国产精品| 中文字幕亚洲一区二区三区五十路| 国产人妖伪娘一区91| 亚洲精品日产aⅴ| 欧美性69xxxx肥| 国产成人免费91av在线| 亚洲电影av在线| 亚洲精品一区久久久久久| 2019中文在线观看| 亚洲网站在线观看| 91视频88av| 亚洲人成网站色ww在线| 久久久久久久国产精品视频| 亚洲欧美三级在线| 亚洲夜晚福利在线观看| 日韩高清电影免费观看完整| 成人免费xxxxx在线观看| 国产亚洲欧洲在线| 日本a级片电影一区二区| 成人免费视频网| 久久久噜久噜久久综合| 国产a∨精品一区二区三区不卡| 欧美日本精品在线| 亚洲精品国产精品久久清纯直播| 欧美在线影院在线视频| 国产精品无av码在线观看| 日韩欧美aⅴ综合网站发布| 日韩久久精品电影| 另类天堂视频在线观看| 国产第一区电影| 成人国内精品久久久久一区| 欧美福利视频在线观看| 日韩欧美在线观看视频| 中文字幕久热精品在线视频| 77777少妇光屁股久久一区| 国产97在线|亚洲| **欧美日韩vr在线| 97超级碰碰人国产在线观看| 欧美成人精品影院| 欧美日韩国产成人在线| 欧美中文字幕视频在线观看| 日韩激情在线视频| 精品国产电影一区| 中文字幕精品国产| 日韩中文字幕视频在线| 欧美插天视频在线播放| 久久久亚洲国产天美传媒修理工| 在线色欧美三级视频| 在线观看国产精品91| 亚洲第一网中文字幕| 日韩高清电影好看的电视剧电影| 国产精品久久久精品| 456国产精品| 久久九九有精品国产23| 欧美日韩在线另类| 精品在线观看国产| 欧美激情国产高清| 国产精品视频地址| 欧美激情日韩图片| 国语自产精品视频在线看抢先版图片| 精品国产鲁一鲁一区二区张丽| 亚洲人成欧美中文字幕| 日韩欧美精品网站| 色综合老司机第九色激情| 性色av一区二区三区红粉影视| 欧美成年人视频网站欧美| 久久久精品国产| 久久国产精品久久久| 亚洲欧美国产精品久久久久久久| 伊人久久五月天| 欧美野外wwwxxx| 日韩精品免费在线视频| 国产精品极品在线| 色琪琪综合男人的天堂aⅴ视频| 亚洲视频自拍偷拍| 最近2019好看的中文字幕免费| 久久久精品一区二区| 91精品久久久久久久久久久| 91久久久国产精品| 欧美精品999| 97精品久久久| 91香蕉国产在线观看| 68精品国产免费久久久久久婷婷| 亚洲国产精品久久久| 精品久久久久久久大神国产| 最近2019中文字幕第三页视频| 国产精品视频男人的天堂|