关于this指向性的问题

函数调用

首先须要从函数的调用开始讲起。浏览器

JS(ES5)里面有三种函数调用形式:app

 

func(p1, p2) 
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不讲 apply



通常,初学者都知道前两种形式,并且认为前两种形式「优于」第三种形式。函数

从看到这篇文章起,你必定要记住,第三种调用形式,才是正常调用形式:this

func.call(context, p1, p2)

其余两种都是语法糖,能够等价地变为 call 形式:spa

func(p1, p2) 等价于
func.call(undefined, p1, p2)

obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)

请记下来。(咱们称此代码为「转换代码」,方便下文引用)code

至此咱们的函数调用只有一种形式:对象

func.call(context, p1, p2)

这样,this 就好解释了

this,就是上面代码中的 context。就这么简单。io

this 是你 call 一个函数时传的 context,因为你历来不用 call 形式的函数调用,因此你一直不知道。console

先看 func(p1, p2) 中的 this 如何肯定:function

当你写下面代码时

function func(){
  console.log(this)
}

func()

等价于

function func(){
  console.log(this)
}

func.call(undefined) // 能够简写为 func.call()

按理说打印出来的 this 应该就是 undefined 了吧,可是浏览器里有一条规则:

若是你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

所以上面的打印结果是 window。

若是你但愿这里的 this 不是 window,很简单:

func.call(obj) // 那么里面的 this 就是 obj 对象了

 

再看 obj.child.method(p1, p2) 的 this 如何肯定

var obj = {
  foo: function(){
    console.log(this)
  }
}

obj.foo()

按照「转换代码」,咱们将 obj.foo() 转换为

obj.foo.call(obj)

好了,this 就是 obj。搞定。

回到题目:

var obj = {
  foo: function(){
    console.log(this)
  }
}

var bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar() 
// 转换为 bar.call()
// 因为没有传 context
// 因此 this 就是 undefined
// 最后浏览器给你一个默认的 this —— window 对象

[ ] 语法

function fn (){ console.log(this) } var arr = [fn, fn2] arr[0]() // 这里面的 this 又是什么呢? 

咱们能够把 arr[0]( ) 想象为arr.0( ),虽而后者的语法错了,可是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,因而就能够愉快的转换了:

arr[0]() 假想为 arr.0() 而后转换为 arr.0.call(arr) 那么里面的 this 就是 arr :) 

 

总结

  1. this 就是你 call 一个函数时,传入的 context。
  2. 若是你的函数调用形式不是 call 形式,请按照「转换代码」将其转换为 call 形式。

之后你遇到全部跟 this 有关的笔试题,都不会有疑问了。

完。

相关文章
相关标签/搜索