盘一盘 this指向 的问题

139 阅读2分钟

在写代码的时候,总是避不开要使用this,今天就来盘一盘它。文中的观点大部分来自于《你不知道的JavaScript》上册。

遇到的问题:

下面这段代码中,为什么 b() 的结果是 undefined

var a = {
    name:'junjun',
    fn:function(){
        console.log(this.name);
    }
}
a.fn() //输出结果:  junjun   
//原因:fn在这里被调用,并且它的上下文对象是a,所以this指向a。

var b = a.fn // b是a的实例,这里的fn并没有被调用
console.log(b) // 输出结果:[Function: fn]  
b()  //输出结果:undefine

按照书(你不知道的JavaScript)中归纳的this绑定规则,b()这种情况属于 默认绑定 规则。所以this被绑定在全局对象上了。 但是在全局对象并上没有 name这个属性。


解决办法->改变this的指向在 call apply bind 中找不同


1. this为什么出现?

当我们的使用模式越来越复杂的时候,显示传递上下文对象会让代码变得越来越混乱,不容易阅读。而this 可以帮助我们更优雅的来隐式 “传递” 一个对象引用。

2. 误区

  • 对JavaScript不太熟悉的同学,可能会认为 this是指向函数本身的。但是this 的指向并不这样被期望的指向了自己
function foo(){
  console.log(this.count +2)
}
foo.count = 0

console.log(foo()) //输出结果: NaN
console.log(foo.count) //输出结果: 0
  • 还有一种说法是:this是指向函数的作用域的。这个说法有点,一半对一般错?

不过需要记住的是this在任何的时候都不会指向函数的词法作用域。词法作用域是,在词法阶段被定义的作用域。

3. 正确的是:

  • this是在运行的时候进行绑定的,并不是在编写的时候绑定。

  • this的绑定和 函数声明所在的位置无关,只和函数被调用时候的位置有关。

当一个函数被调用的时候,会创建一个活动记录(执行上下文),这个活动记录包括:在哪里被调用(调用栈),函数的调用方式,传入的参数等,而this就是这个活动记录中的一个属性,会在函数执行的过程中用到。

4. this 的绑定规则

  • 默认规则(没有匹配到其他的绑定规则):在严格模式下,绑定到undefined。 普通模式下,绑定到全局对象上。
  • new 绑定:出现在构造函数处。绑定新创建的对象。
  • 隐式绑定:在某个上下文对象中被调用,this就绑定到那个上下文对象中。
  • 显式绑定:通过call ,apply,和bind 或者硬绑定,就绑定到它们指定的对象 上。