您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

JavaScript 中的 this 的七种使用情况

时间:12-27来源:作者:点击数:
CDSY,CDSY.XYZ

由于严格模式下,禁止 this 指向全局对象,所以以下示例均运行在非严格模式下

情况一:全局 & 调用普通函数

console.log(this === window);   //true

普通函数在调用时候(注意不是构造函数,前面不加 new),其中的 this 也是指向 window。

var x = 10;
function foo(){
  console.log(this);   //Window
  console.log(this.x);   //10
}
foo();

情况二:构造函数

所谓的构造函数就是由一个函数 new 出来的对象,一般构造函数的函数名首字母大写,例如像 Object,Function,Array 这些都属于构造函数。

function Foo(){
  this.x = 10;
  console.log(this);  //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x);    //10

上述代码,如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象。

但是如果直接调用 Foo 函数,而不是 new Foo(),那就变成情况1,这时候 Foo() 就变成普通函数。

function Foo(){
  this.x = 10;
  console.log(this);  //Window
}
var foo = Foo();

情况三:对象方法

如果函数作为对象的方法时,方法中的 this 指向该对象。

var obj = {
  x: 10,
  foo: function () {
    console.log(this);    //Object
    console.log(this.x);    //10
  }
};
obj.foo();

注意:若是在对象方法中定义函数,那么情况就不同了。

var obj = {
  x: 10,
  foo: function () {
    function f(){
      console.log(this);    //Window
      console.log(this.x);  //undefined
    }
    f();
  }
}
obj.foo();

可以这么理解:函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window。

在这里,如果想要调用上层作用域中的变量 obj.x,可以使用 self 缓存外部 this 变量。

var obj = {
  x: 10,
  foo: function () {
    var self = this;
    function f(){
      console.log(self);    //{x: 10}
      console.log(self.x);  //10
    }
    f();
  }
}
obj.foo();

如果 foo 函数不作为对象方法被调用:

var obj = {
  x: 10,
  foo: function () {
    console.log(this);     //Window
    console.log(this.x);   //undefined
  }
};
var fn = obj.foo;
fn();

情况四:构造函数 prototype 属性

function Foo(){
  this.x = 10;
}
Foo.prototype.getX = function () {
  console.log(this);    //Foo {x: 10, getX: function}
  console.log(this.x);    //10
}
var foo = new Foo();
foo.getX();

在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。

情况五:函数用 call、apply 或者 bind 调用

var obj = {
  x: 10
}
function foo(){
  console.log(this);   //{x: 10}
  console.log(this.x);   //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();

当一个函数被 call、apply 或者 bind 调用时,this 的值就取传入的对象的值。

情况六:DOM event this

function Listener(){   
  document.getElementById('foo').addEventListener('click', this.handleClick);   //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
}
Listener.prototype.handleClick = function (event) {
  console.log(this);  //<div></div>
}
var listener = new Listener();
document.getElementById('foo').click();

这个很好理解,就相当于是给函数传参,使 handleClick 运行时上下文改变了,相当于下面这样的代码:

var obj = {
  x: 10,
  fn: function() {
    console.log(this);     //Window
    console.log(this.x);     //undefined
  }
};
function foo(fn) {
  fn();
} 
foo(obj.fn);

你也可以用通过 bind 切换上下文:

function  Listener(){
  document.getElementById('foo').addEventListener('click',this.handleClick.bind(this));    
}
Listener.prototype.handleClick = function (event) {
  console.log(this);  //Listener {}
}
var listener = new Listener();
document.getElementById('foo').click();

前六种情况其实可以总结为: this 指向调用该方法的对象。

情况七:箭头函数中的 this

当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域,由上下文确定。

var obj = {
  x: 10,
  foo: function() {
    var fn = () => {
      return () => {
        return () => {
          console.log(this);    //Object {x: 10}
          console.log(this.x);  //10
        }
      }
    }
    fn()()();
  }
}
obj.foo();

现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 obj。

如果使用箭头函数,以前的这种 hack 写法:

var self = this;

就不再需要了。

var obj = {
  x: 10,
  foo: function() {
    var fn = () => {
      return () => {
        return () => {
          console.log(this);  // Object {x: 10}
          console.log(this.x);  //10
        }
      }
    }
    fn.bind({x: 14})()()();
    fn.call({x: 14})()();
  }
}
obj.foo();

由于 this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略。

CDSY,CDSY.XYZ
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐