乐趣区

深入浅出JavaScript之this

深入 浅出 JavaScript 之 this

JavaScript 中的 this 比较灵活,根据在不同环境下,或者同一个函数在不同方式调用下,this 都有可能是不同的。但是有一个总的原则,那就是 this 指的是,调用函数的那个对象。

全局的 this(浏览器)

全局作用域的 this 一般指向全局对象,在浏览器中这对象就是 window,在 node 中这对象就是 global。

一般函数的 this(浏览器)

一般的函数声明或者函数表达式,直接调用函数的话,this 依然指向全局对象,在浏览器中这对象就是 window,在 node 中这对象就是 global。

再举一个例子,看完就非常透彻了


为了证明 this 就是全局对象,对代码做一些改变:


运行结果还是 1。再变一下:


但是在严格模式下,一般函数调用的时候 this 指向 undefined,这也是 node 为什么要用严格模式的一个原因。

作为对象方法的函数的 this

this 作为对象方法来使用是比较常见的。

下面这个例子,我们创建了一个对象字面量 w,w 里面有个属性 ff,它的值是一个函数对象,把函数作为对象属性的值这种方式我们常常叫作对象的方法。作为对象的方法调用的时候,这时候 this 指向对象 w


我们不一定要定义成函数字面量这样子的对象,像下面这种情况,我们只定义了一个对象 s,如果直接调用 independent()函数的话,this 会指向 window,但是我们通过赋值的方式,临时创建一个属性 ff, 并指向函数对象的时候,我们仍然拿到了 11。

所以并不是看函数是怎么创建的,而是只要将函数作为对象的方法去调用,this 就会指向这个对象。

对象原型链上的 this

下面这个例子中: 我们先创建了一个对象 a, 里面有一个属性 ff, 函数作为对象属性的值,我们通过 Object.create(o)创建了一个对象 p,p 是一个空对象,它的原型会指向 a, 然后使用 p.a = 1; p.b = 4 创建对象 p 上的属性,那么我们调用原型上的方法时,this.a,this.b 依然能取到对象 p 上的 a 和 b。这里需要注意的是 p 的原型才是 a,我们调用 p.f(),调用的是原型链 a 上的属性 f,原型链上的 this 可以拿到当前的对象 p。

get/set 方法与 this

get/set 方法中的 this 一般会指向 get/set 方法所在对象里面

构造函数中的 this

用 new 把 MyClass 作为构造函数调用的话,this 会指向空的对象,并且这个对象的原型会指向 MyClass.prototype(可以看这篇文章对原型链的总结), 但是调用的时候做了 this.a = 37 的赋值, 所以最后 this 会作为返回值(没写 return 语句, 或者 return 的是基本类型的话, 会将 this 作为返回值),第二个例子 return 语句返回了对象,那么就会将 a = 38 作为返回值

call/apply 方法与 this

除了不同的调用方式外,函数对象有些方法能修改函数执行的 this,比如 call/apply。

call 和 apply 基本上没差别,只不过 call 传参的方式是扁平的,而 apply 是把一个数组传进去。如下面这个例子

什么时候用 call 和 apply 呢?比如我们想调用 Object.prototype.toString, 但是我们想指定某个 this 的时候,那我们就可以就用 Object.prototype.toString.call(this)这样子的方式来调用些无法直接调用的方法。如下面这个例子:

bind 方法与 this

bind 方法是 es5 开始提供的,所以 ie9+ 才支持

总结

做项目的时候会发现这些基础概念有多么的重要,如果不把它们逐个落实了,真的是一不小心就会掉进坑里。

退出移动版