理解 this

2019-06-27  本文已影响0人  lyp82nkl

函数调用

通常有三种函数执行方式
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)
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
}`

例题2:

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

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

例题3:

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

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

特殊情况:自己抢先的调用 它,自己去 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 的理解,方老师的这篇 文章 很完美

上一篇下一篇

猜你喜欢

热点阅读