美文网首页
理解 this

理解 this

作者: lyp82nkl | 来源:发表于2019-06-27 02:18 被阅读0次

    函数调用

    通常有三种函数执行方式
    func(a, b) 
    obj.child.fn(a, b)
    func.call(context, a, b) 
    

    一般来说前面两种方式大家用的比较多,但是其实第三种才是函数调用的本质。

    fn.call(context, a, b)
    

    其他两种可以等价地变为 call 形式:

    fn(a, b)
    // 等价于
    fn.call(undefind, a, b)
    
    obj.child.fn(a, b)
    // 等价于
    obj.child.fn.call(obj.child, a, b)
    
    • 严格模式,fn的this就是call第一个参数undefined
    • 非严格模式,call 传递的第一个参数如果是 undefined 或者 null, 那 this 会自动替换为 Window 对象
      函数执行的本质:函数的执行,都可以等价看做为fn.call的调用
    var obj = {
       fn: function(a, b){
           console.log(this)
       },
       child: {
           fn2: function(){
               console.log(this)
           }
       }
    }
    
    obj.fn(2, 3)
    // 等价
    obj.fn.call(obj, 2, 3)  // fn的this 为 obj
    
    obj.child.fn2()
    // 等价
    obj.child.fn2.call(obj.child) // fn2的this 为 obj.child
    

    this 就是你 call 一个函数时,传入的第一个参数。

    例题1:

    button.onclick = function f1(){
    console.log(this)   // 触发事件的元素。 button
    }`
    
    • this 是什么?去看 onclick 的源码呀 -> 做不到
    • MDN 的开发者知道 onclick 的源码
    • MDN 的开发者写了文档
    • 看文档

    例题2:

    button.addEventListener('click', function(){
    console.log(this) //该元素的引用 button
    })
    

    https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener

    • 去看 addEventListener 的源码呀 -> 做不到
    • MDN 的开发者知道 addEventListener 的源码
    • MDN 的开发者写了文档
    • 看文档

    例题3:

    $('ul').on('click', 'li', function(){     //  li  是  selector 
    console.log(this) //this 则代表了与 selector 相匹配的元素
    // 这里的 this 是某个 li  元素
    })
    })
    

    当jQuery的调用处理程序时,this关键字指向的是当前正在执行事件的元素。对于直接事件而言,this 代表绑定事件的元素。对于代理事件而言,this 则代表了与 selector 相匹配的元素。若要使用 jQuery 的相关方法,可以根据当前元素创建一个 jQuery 对象,即使用 $(this)。

    • 去看 on 的源码呀 -> 做不到
    • jQuery 的开发者知道 onclick 的源码,f1.call(???)
    • jQuery 的开发者写了文档
    • 看文档

    特殊情况:自己抢先的调用 它,自己去 call.
    button.onclick.call({name:'xxx'}) //this 是 xxx
    只要没看见 call ,就不知道 this 什么。因为 this 是 call 的第一个参数

    例题4:

    function x(){
      return object = {
        name: 'object',
    options: null,
        f1(x){
          this,options = x  //所以这个 this 是外面的 x ,外面的 x 就是object 
    this.f2()  //这个 this 是 f1 call 的第一个参数 ,所以这个this 就是  object
       },
        f2(){
         this.options.f2.call(this) //这个 this 也是 object
    // 这个 this.options.f2 就是 x.f2 
    // x.f2 也就是 options.f2
    // 也就是调用下面的 options 的 f2 函数, 
    //调这个函数传了一个 this,这个this 就是  object
        }
      }
    }
    
    var options = {
      name: 'options',
      f1(){},
      f2(){
        console.log(this)  //this 是啥?
      }
    }
    
    var x = X()
    x.f1(options) //call 的第一个参数是 x
    

    问:options 中 f2 的 this 是啥?
    答:object

    this.f2() 中的 this 是 x.f1(options)call 的第一个参数 ,call的第一个参数是 x.
    ,所以this.f2() 中this 是外面的 x , 外面的 x 就是 object 。this.f2() 中this 就是 object。
    f2(){ this.options.f2.call(this) } 这个 this 也是 object。
    this.options =x , 这个 this.options.f2 就是 x.f2
    x.f2 也就是 options.f2,因为 x.f1(options)传的参数是 options。也就是调用 options 的 f2 函数,调这个函数传了一个 this,这个this 就是 object

    例题5:

    var a = {
      p: 'Hello',
      b: {
        m: function() {
          console.log(this.p);
        }
      }
    };
    
    a.b.m()
    

    上面的a.b.m()执行后里面的this.p是什么?

    答:因为前面说了,this就是函数call的第一个参数,上面的a.b.m()写成call的形式就是a.b.m.call()也就是(a.b).m.call(a.b),所以this是a.b,也可以而b里面没有p所以是undefined

    例题6:

    var obj = {
        fn(){
            return function(){
                console.log(this)
            }
        },
        f1(){
            var f =this.fn()
            f()
        }
    }
    obj.f1()
    

    上面的代码因为是普通函数里的this,所以与它调用的时候有关,因为它是return的所以实际上就是f()的时候调用的,转成f.call(undefined),this就是window

    例题7:

    var obj = {
        fn(){
            return ()=>{
                console.log(this)
            }
        },
        f1(){
            var f =this.fn()
            f()
        }
    }
    obj.f1()
    

    上面的代码因为this是在一个箭头函数里,所以直接忽略,它的this就是它的外层函数fn里的this,而fn是普通函数,所以它的this就是它在调用的时候call的第一个参数,也就是this.fn.call(this)这里的this就是f1这个函数被调用时的this,也就是obj.f1.call(obj)所以this是obj

    例题8:

    window.xx = 'hhhhhhhhhh'
    
    let c = {
      xx:'name',
      find(){
        console.log(this.xx)
      },
      throttle(fn){
        var timer = null
        return ()=>{
          clearTimeout(timer)
          timer = setTimeout(()=>{
            fn()
          },1000)
        }
      },
    
      bindEvent(){
        var f = this.throttle(this.find)
        f()
      }
    }
    c.bindEvent()
    

    上面的find里的this是什么?
    答:是window,因为函数里的this只与函数被调用时有关,如果不是箭头函数,那这个函数调用的时候只需要转成call的形式就能知道this了,上面的find函数也就是fn,fn被调用的时候是fn(),因为find本身不是箭头函数,所以可以转成fn.call(undefined),所以this是window

    例题9:

    对于class中的this,如果是被直接call(undefined)那么this就是undefined

    class Animal { 
      speak() {
        return this;
      }
      static eat() {
        return this;
      }
    }
    let obj = new Animal();
    let speak = obj.speak;
    speak(); // undefined
    

    上面的speak()转成call的形式就是speak.call(undefined),因为class中所有的函数、方法、构造函数、getters或setters都在严格模式下执行。因此如果我们没有指定this的值,也就是call的时候传入的是undefined那么this就是undefined

    有关 this 的理解,方老师的这篇 文章 很完美

    相关文章

      网友评论

          本文标题:理解 this

          本文链接:https://www.haomeiwen.com/subject/bwpkcctx.html