详解JavaScript中this的指向

来源:互联网 发布:宝贝标题优化工具 编辑:程序博客网 时间:2024/05/16 16:08

JavaScript中this的指向

之前一直不明白JavaScript中this的指向,觉得很容易混淆,今天研究了一下,豁然开朗,分享一下。

全局变量this

在browser环境中,this指向的是window对象。

console.log(this); // window

在node环境中,this指向的不是global对象,它指向一个空对象,而这个空对象其实是module.exports。

console.log(this); // {}console.log(this === module.exports); // true

函数中的this

一个函数,其this指向全局对象。

function foo() {  console.log(this);}foo(); // browser指向window,node指向global

如果使用了严格模式,this都指向undefined。

'use strict';function foo() {  console.log(this);}foo(); // browser和node都指向undefined

我们可以使用call()或者apply()来改变函数运行时this的指向。

function foo() {  console.log(this.name)}foo.call({ name: 'obj' }); // obj

由于函数的this指向全局对象,所以如果函数中嵌套一个函数,就算在调用时改变了函数的this指向,但被嵌套函数的指向也会重新指向全局对象。这其实是JavaScript中的一个设计缺陷,正常来讲,被嵌套函数的this应该指向其上一级函数的this。

var name = 'global';function foo() {  console.log(this.name); // obj  function bar() {    console.log(this.name); // global  }  bar();}foo.call({ name: 'obj' });

可以这样来解决:

var name = 'global';function foo() {  console.log(this.name); // obj  var that = this;  function bar() {    console.log(that.name); // obj  }  bar();}foo.call({ name: 'obj' });

构造函数中的this

如果在函数前加new,那么this指向这个构造函数实例。

function Foo() {  console.log(this);}new Foo(); // Foo() {}

对像方法中的this

谁调用这个方法,this就指向谁。

var name = 'global';var o1 = {  name: 'o1',  foo: function() {    console.log(this.name);  }}var o2 = {  name: 'o2',  foo: function() {    console.log(this.name);  }}o1.foo(); // o1o2.foo(); // o2var f = o1.foo;f(); // globalo1.foo.call(o2); // o2

使用一个变量接收方法后再调用,相当于调用了一个函数,根据JavaScript的设计,函数的this指向全局对象,所以输出global。(node环境会输出undefined)

ES6箭头函数的this

箭头函数是ES6的新特性,它的作用是:

  • 语法糖,简化了函数的声明
  • 修复了JavaScript函数中this的指向问题

使用传统的方式声明函数,函数中的this指向全局变量,在嵌套函数的情况下,这个特性就比较糟糕了,而ES6新出现的箭头函数修正了这个问题。

箭头函数中并没有自己的this,它的this指向其所在作用域中的this,在编写代码时就能体验出来:声明时就已经确定指向,在哪个作用域中声明,就指向那个作用域中的this,且运行时不能改变其指向。

var name = 'global';var foo = () => {  console.log(this.name);}foo(); // globalfoo.call({ name: 'obj' }); // global

可以看到,foo是在全局作用域中声明的,全局作用域中this指向window对象,所以foo()的this也指向window,它的指向是声明时就已经确定,所以使用call()不能改变其this。

另一个例子:

var name = 'global';function foo() {  var bar = () => {    console.log(this.name);  }  bar();}foo.call({ name: 'obj' }); // obj

foo()函数是声明式函数,可以使用call()改变其this的指向,而bar是箭头函数,它在foo()函数的作用域中声明,所以其this的指向为foo()中this的指向,最终输出obj。

由于箭头函数没有自身的this,所以它不能用作构造函数。

var Foo = () => {  this.name = 'foo';}new Foo(); // TypeError: Foo is not a constructor

以上,如有理解错误的地方请指出,谢谢。

原创粉丝点击