最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript中的This指向汇总

    正文概述 掘金(Joe_cat)   2020-12-11   310

    关于js中this的处理情况汇总

    1. 给当前元素的某个时间行为绑定方法,当事件行为触发,方法被执行,方法中的this一般都是当前操作的元素 (排除IE6 - 8 中给予attachEvent进行的DOM2事件绑定,方法中的this是window)

      document.body.onclick = function(){
          console.log(this) // <body>...</body>
      }
      document.body.addEventListener('click', function(){
          console.log(this) // <body>...</body>
      })
      
    2. 函数执行,看函数前面是否有点.,有点.,点前面是谁this就是谁,没有点.this就是window

      • js严格模式下,没有点.this就是undefined
      • 匿名函数(自执行函数/回调函数)一般this也是window/undefined,除非有特殊处理的
      • 括号表达式中有特殊的处理
      const fn = function(){
          console.log(this)
      }
      let obj = {
          name: 'obj',
          fn: fn
      }
      fn();  // 根据第一条,没有点 this => window
      obj.fn() // 有点,点前面使obj, this => obj
      

      严格模式下

      "use strict"
       const fn = function(){
      	console.log(this)
      }
      let obj = {
          name: 'obj',
          fn: fn
      }
      fn();  // 根据严格模式下第一条,没有点 this => undefined
      obj.fn() // 有点,点前面使obj, this => obj
      

      自执行函数

      (function(){
          console.log(this)  // this => window
      })()
      

      严格模式自执行函数

      "use strict"
      (function(){
          console.log(this)  // this => undefined
      })()
      

      回调函数

      [1, 2].sort(function(a, b){
          console.log(this) // this => window
      })
      

      注意:下面的这个将会发生改变

      [1].forEach(function(item, index){
         console.log(this) // this => obj
      }, obj)
      

      说明:看到这个结果并不符合我们上面的总结,这是因为forEach内部做了特殊的处理,传递的第二个参数是为了改变回调函数中的this指向的

      括号表达式

      let obj = {
          name: 'obj',
          fn: fn
      }
      
       function fn(){
          console.log(this)
      }
      
      (obj.fn)() // this => obj
      

      说明:括号表达式中只包含一项时与不加括号是没有任何区别的

      let obj = {
          name: 'obj',
          fn: fn
      }
      function fn(){
          console.log(this)
      }
      (10, 20, obj.fn)();  // this => window
      

      说明:括号表达式中存在多项时,也只取最后一项,但是此时的this变为window。可以理解为将括号表达式中的最后一项克隆一份,然后自执行。

    3. 构造函数执行new xx,函数体中的this是当前类的实例

      function Fn(){
          this.x = 100;
      } 
      Fn()  // this => window
      let f = new Fn(); // this => f
      f.sum(); // this => f
      f.__proto__.sum(); // this => f.__proto__
      

      说明:上面的例子并不适用直接粘贴复制,只是为了说明

    4. ES6中的箭头函数(或者基于{}形成的块级上下文)里面没有this,如果代码中遇到this也不是自己的,而是它上下文中的this

       let obj = {
          name: 'obj',
          fn() {
              // this => obj
              setTimeout(function(){
                  console.log(this); // this => window (回调函数)
                  this.name = 'joe'; // 这里改变的window.name 
              }, 1000)
          }
        }
        obj.fn();
      
      // 方法一 将 this指向obj时进行存储
       let obj = {
          name: 'obj',
          fn() {
              // this => obj
              let that = this;
              setTimeout(function(){
                  that.name = 'joe'
              }, 1000)
          }
        }
        obj.fn();
           
       // 方法二 使用箭头函数
       let obj = {
          name: 'obj',
          fn() {
              // this => obj
              setTimeout(() => {
                  // this => 用的使上级上下文中的this,也就是obj
                  this.name = 'joe';
              }, 1000)
          }
        }
        obj.fn();
      
    5. 我们可以基于Function.prototype上的call/apply/bind方法强制改变 函数中的this指向

      • 对箭头函数没用,因为不存在this
      // 1
      const fn = function fn(){
          console.log(this.name)
      }
      window.name = 'joe';
      let obj = {
          name: 'obj',
      }
      fn(); 	// 'joe'
      fn.call(obj)  // 'obj'
      obj.fn()  // Uncaught TypeError: obj.fn is not a function 
         
         
      // 2
      const fn = function fn(x, y){
          this.total = x + y;
          console.log(this);
          return this;
      }
      window.name = 'joe';
      let obj = {
          name: 'obj',
      }
      let res = fn.call(obj, 10, 20)  // this => obj res => obj
      

      分析call语法

      函数.call([context], params1, params2, ...)

      简单说明:把函数中的this指向[context],并把params1/params2...作为实参传递给函数

      详细说明

      • 首先fn基于原型链__proto__,找到Function.prototype.call方法,并把call方法执行

      • call方法中的this就是当前操作的实例 fn,传递给call方法的第一个实参是改变fn中的this指向,剩余的实参都是未来要依次传递给fn的参数信息

      • call方法执行的过程中,实现了这样的处理:把 fn[call中的this]指向[context],并且把params1/params2...作为实参传递给fn,依次来达到最后的效果

      • 最后接受fn的返回结果,作为返回值返给外部

      结论

      • 执行fn.call(10, 20)此时this则为10, 说明第一个参数传递的是什么则this指向就是什么

      • 执行fn.call()无参数时thiswindow,如果第一个参数是null或者undefined,在JavaScript非严格模式下,最后fn中的this都是window(严格模式下,不传thisundefined,传递nullundefinedthis也会改为对应的值)

      apply

      函数.call([context], [params1, params2, ...])

      callapply的唯一区别:执行函数的时候,需要传递给函数的参数信息,在最开始传递给call/apply的时候,形式不一样

      • call需要把参数一个个传递给callcall方法内部再一个个传递给函数

      • apply是需要把参数放在一个数组中传递给apply,但是apply内部也会帮我们把接受数组中的每一项一项一项的传递给函数

      bind

      call/apply在执行的时候,都会立即把要操作的函数执行,并且改变它的this指向

      bind预先处理:执行bind只是把函数中需要改变的this等信息存储起来,但是此时函数并不会被执行,执行bind会返回一个匿名函数,当后期执行匿名函数的时候,再去把之前需要执行的函数执行,并且改变this为预设的值

      此时执行fn.bind(obj, 10, 20)bind执行但是fn是不会执行的。

      let anonymous = fn.bind(obj, 10, 20);
      console.log(anonymous) 
      // ƒ fn(x, y){
      //    this.total = x + y;
      //    console.log(this);
      //    return this;
      // }
      

      说明:anonymous的值为一个函数,也就是说后期把返回的函数anonymous在执行,在里面才会把fn执行,并且按照预设的信息改变this

      // 错误答案 请思考一下原因
         
      // 1.
      setTimeout(fn, 1000); // 1000ms 后执行fn,但是this => window, x/y都是undefined
         
      // 2
      setTimeout(fn.call(obj, 10, 20), 1000)  // 因为设置定时器时,基于call方法,就已经把fn执行了,虽然this和参数都是我们想要的,但是并不是1s后执行。就是把fn的返回结果邦洞给定时器,1000 ms后执行的使返回结果 
         
      // 正确答案
      // 1. 
      setTimeout(function(){
      	fn.call(obj, 10, 20)
      }, 1000)
         
      // 2.
      setTimeout(fn.bind(obj, 10, 20), 1000) 
      

    最后

    biu biu biu ~ ❤️❤️❤️❤️ 点关注 ?? 不迷路 点个赞哦?


    起源地下载网 » JavaScript中的This指向汇总

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元