资讯专栏INFORMATION COLUMN

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

hiYoHoo / 2553人阅读

摘要:这里就不讲述两者的不同了基本就是两个函数的参数使用不一致引入了。调用会创建一个与具有相同函数体和作用域的函数,但是在这个新函数中,将永久地被绑定到了的第一个参数,无论这个函数是如何被调用的。

JavaScript的this

在JavaScript中this是一个永恒的话题,正在能够完全掌握其实不易,本文主要讲解下一下几种情况下的判定:

全局情况下

对象调用下

call、apply、bind方法

dom事件绑定

setTimeout、setInterval

ajax等异步操作

全局window/global

一个在模块或者全局的情况下调用一个方法时【不在使用 "use strict"的情况,否则不会默认将this指向全局】

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

可以知道,在这种情况下的this一般是window或者node中的global;

对象调用

这里可能是方法作为构造函数来使用,那么这个方法中的this会指向这个构造方法的实例,

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

可以看到,在一些情况下如果出现了类似的调用写法的话,this一般指向的就是调用者本身,形如【object.fn()】,这种情况下的fn里面的this一般指向前面调用fn方法的object对象;

call、apply、bind方法

apply()和call()是函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数。这里就不讲述两者的不同了【基本就是两个函数的参数使用不一致】;

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...

dom事件绑定

在使用js操作dom的时候,很常见的会绑定事件;比如下面的将元素p绑定click事件,然后事件的回调函数中就可以使用this;this指向这个时间的目标元素,也就是绑定事件的具体元素;

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

而在jQuery的使用中我们基本就是使用$(this)来表示事件的目标元素;因为this就是e.target;而把一个dom元素变为jQuery元素就是使用$把他抱起来就好了;

setTimeout、setInterval的this

在js中,window实现了WindowOrWorkerGlobalScope这个mixin的所有方法,其中最被经常使用的就是setTimeout、setInterval,因为这是一个异步的过程:

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这面目,也就是上面的格式的数据。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91406.html

相关文章

  • Javascript定时器那些事儿

    摘要:一什么是定时器提供了一些原生方法来实现延时去执行某一段代码,下面来简单介绍一下设置一个定时器,在定时器到期后执行一次函数或代码段定时器延迟后执行的函数延迟后执行的代码字符串,不推荐使用原理类似延迟的时间单位毫秒,默认值为向延迟函数传递而外的 一、什么是定时器 JS提供了一些原生方法来实现延时去执行某一段代码,下面来简单介绍一下 setTimeout: 设置一个定时器,在定时器到期后执行...

    Riddler 评论0 收藏0
  • 关于javascript高级定时器若干问题

    摘要:闭包闭包是指有权访问另一个函数作用域中的变量的函数当某个函数被调用时,会创建一个执行环境及相应的作用域链。要注意通过第句声明的这个方法属于构造函数生成的对象,而不属于构造函数的变量对象,也就是说,并不存在于作用域链中。 看到评论里有仁兄建议我试试箭头函数,真是受宠若惊,本来写这篇文章也只是想记录写要点给自己日后看的。今天早上看到一篇总结javascript中this的文章JavaScr...

    zr_hebo 评论0 收藏0
  • JavaScriptthis

    摘要:在中,只有两种指向,一种是指向当前的封闭作用域,或者是指向当前作用域的外层,的最顶层就是对象。在非严格模式下,默认指向全局对象。浏览器环境全局函数方法用于在指定的毫秒数后调用函数或计算表达式。它会不停地调用函数,指导被调用或者窗口被关闭。 1:基本概念 this字面意思是当前,当前执行代码的环境对象或者是上下文。代表着当前方法执行的环境上下文,那么何为环境上下文,通俗的说,谁调用了函数...

    cucumber 评论0 收藏0
  • 细说 Javascript 拾遗篇(四) : setTimeoutsetInterval

    摘要:当间隔时间设置较小时,将会导致回调函数堆积。处理可能阻塞的代码最简单且最可控的方式就是在回调函数内部使用函数。但是很明显,由于指定最大值的限制,还会有定时器没有被清除掉。另外,尽量避免使用函数,从而避免可能导致的回调函数堆积现象。 由于 Javascript 是异步的,因此我们可以通过 setTimeout 和 setInterval 函数来指定特定时间执行代码。 function ...

    wangjuntytl 评论0 收藏0
  • 菜鸟理解setTimeoutsetInterval

    摘要:也就是说,这仅仅是计划在未来某一个时间执行某个任务,并不能保证精确的时间。重复执行问题这个方法执行时仅当没有该计时器的其他代码示例时才进行下一轮的执行。这样的规则就会导致某些间隔会被跳过,同时多个间隔可能比预期时间要短。 写在前面,最近在准备校招,陆陆续续做一些之前的总结,写了一个小系列的文章,想借此机会记录下来,也能以后有个地方能进行查阅,上一篇文章在css基础总结希望能帮助一下和我...

    sixleaves 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<