JavaScript的this指向、setTimeout、setInterval、ajax-callback

JavaScript的this

在JavaScript中this是一個永恆的話題,正在可以徹底掌握其實不易,本文主要講解下一下幾種狀況下的斷定:javascript

  • 全局狀況下
  • 對象調用下
  • call、apply、bind方法
  • dom事件綁定
  • setTimeout、setInterval
  • ajax等異步操做

全局window/global

一個在模塊或者全局的狀況下調用一個方法時【不在使用 'use strict'的狀況,不然不會默認將this指向全局】php

var x = 9;
  function test(){
    this.x = 6;
  }
  test();
  alert(x); //輸出6

能夠知道,在這種狀況下的this通常是window或者node中的global;html

對象調用

這裏多是方法做爲構造函數來使用,那麼這個方法中的this會指向這個構造方法的實例,java

 function test(){
    this.x = 1;
  }
  var o = new test();
  alert(o.x); // 1

能夠看到,在一些狀況下若是出現了相似的調用寫法的話,this通常指向的就是調用者自己,形如【object.fn()】,這種狀況下的fn裏面的this通常指向前面調用fn方法的object對象;node

call、apply、bind方法

apply()和call()是函數對象的一個方法,它的做用是改變函數的調用對象,它的第一個參數就表示改變後的調用這個函數的對象。所以,this指的就是這第一個參數。這裏就不講述二者的不一樣了【基本就是兩個函數的參數使用不一致】;jquery

var x = 0;
  function test(){
    alert(this.x);
  }
  var o={};
  o.x = 1;
  o.m = test;
  o.m.apply(); //0
    o.m.apply(o); //1

ECMAScript 5 引入了 Function.prototype.bind。調用f.bind(someObject)會建立一個與f具備相同函數體和做用域的函數,可是在這個新函數中,this將永久地被綁定到了bind的第一個參數,不管這個函數是如何被調用的。也和call、apply用相同做用;
以上參考了:http://www.ruanyifeng.com/blo...
https://developer.mozilla.org...ajax

dom事件綁定

在使用js操做dom的時候,很常見的會綁定事件;好比下面的將元素p綁定click事件,而後事件的回調函數中就可使用this;this指向這個時間的目標元素,也就是綁定事件的具體元素;json

function bluify(e){
  console.log(this === e.currentTarget); // 老是 true
  // 當 currentTarget 和 target 是同一個對象是爲 true
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}
// 獲取文檔中的全部元素的列表
var elements = document.getElementsByTagName('p');
// 將bluify做爲元素的點擊監聽函數,當元素被點擊時,就會變成藍色
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

而在jQuery的使用中咱們基本就是使用$(this)來表示事件的目標元素;由於this就是e.target;而把一個dom元素變爲jQuery元素就是使用$把他抱起來就行了;app

setTimeout、setInterval的this

在js中,window實現了WindowOrWorkerGlobalScope這個mixin的全部方法,其中最被常用的就是setTimeout、setInterval,由於這是一個異步的過程:dom

var x = 33;
var test = { 
    x: 22,
    test:function(){
        console.log(this.x)
    },
    time:function(){
        setTimeout(this.test,1000);
    }
}
test.time(); //輸出33,不是22

在使用異步的setTimeout、setInterval時候,因爲須要等待特定時間以後在進行執行,因此這個就和setTimeout、setInterval的執行有關,在https://zhuanlan.zhihu.com/p/...https://jakearchibald.com/201... 中能夠知道,其實就是event loop的概念,因此其實在使用setTimeout、setInterval的時候會出現等待的時長並非精準的參數中寫入的時間,緣由以下:

  • setTimeout、setInterval會把參數中的函數單獨放在macrotask中,這裏面是須要執行的event隊列;
  • 當計時到達時,從macrotask提早須要定時執行的函數,等待當前正在執行的事件隊列執行完成【這裏還有當前macrotask後面的mairotask】這裏的當前正在執行的就是引發計時不許確的緣由;
  • 當執行完當前的macrotask+microtask之後,就開始執行定時函數,這個時候因爲是新的全局下執行這個函數【這個時候就和本文第一種說的全局下調用function同樣了,this指向window】,因此this會被window覆蓋掉,故而不是在編寫setTimeout時的執行上下文,函數的[[scrope]]時候的this,
  • 具體的macrotask+microtask能夠參考https://zhuanlan.zhihu.com/p/...https://jakearchibald.com/201...

故而解決方法以下:

  • 把this重命名保存:self=this;這樣self仍是函數[[scrope]]中的this;而不會被window替換
  • 使用bind把this綁定
  • 使用當即執行函數來函數再包一層
this.intervalID = setInterval(
        (function(self) {     //Self-executing func which takes 'this' as self
            return function() {    //Return a function in the context of 'self'
                   self.retrieve_rate();   //Thing you wanted to run as non-window 'this'
               }
         })(this),
     this.INTERVAL     //normal interval, 'this' scope not impacted here.
 );

ajax中的this

在ajax中咱們都會很是謹慎的使用this;這個異步操做在this上也是和setTimeout差很少,確定是會被覆蓋的,可是並非被window覆蓋,相反而是被XMLHttpRequest對象覆蓋:

{
    "url": "demo_test.txt",
    "type": "GET",
    "isLocal": false,
    "global": true,
    "processData": true,
    "async": true,
    "contentType": "application/x-www-form-urlencoded; charset=UTF-8",
    "accepts": {
        "*": "*/*",
        "text": "text/plain",
        "html": "text/html",
        "xml": "application/xml, text/xml",
        "json": "application/json, text/javascript",
        "script": "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
    },
    "contents": {
        "xml": {},
        "html": {},
        "json": {},
        "script": {}
    },
    "responseFields": {
        "xml": "responseXML",
        "text": "responseText",
        "json": "responseJSON"
    },
    "converters": {
        "text html": true
    },
    "flatOptions": {
        "url": true,
        "context": true
    },
    "jsonp": "callback",
    "dataTypes": [
        "text"
    ],
    "crossDomain": false,
    "hasContent": false
}

上面是一個ajax中的this的json格式,測試地址:http://www.runoob.com/try/try... 只須要在ajax的回調中打印this【console.log(JSON.stringify(this))】就能夠在開發者工具的console中看到this這面目,也就是上面的格式的數據。

相關文章
相關標籤/搜索