前端开发那些事Web前端之路前端开发部落

JavaScript中的this指针

2018-04-15  本文已影响29人  小道小姐姐

JavaScript函数中的关键字this是自动获得的,因此,了解在不同的情况下this值指向的对象可以帮助我们减少程序中很多'莫名其妙'的bug.

全局上下文

在全局执行上下文中,this指向全局对象(browser: window, node: global),不管是严格模式还是非严格模式。

函数上下文

在函数中,this值取决与函数是如何调用的。

简单调用(不作为对象的方法或属性)

  function foo1() {
    return this;
  }
    
  console.log(foo1() === window); // true
  function foo2() {
    'use strict';
    return this;
  }

  console.log(foo2() === undefined); // true

作为对象的方法

当函数作为对象的方法或属性时,它的this值将被设为调用该方法的对象:

  var o = {
    prop: 37,
    f() {
      return this.prop;
    }
  };
  console.log(o.f()); // 37

即使是通过对象字面量的方法将一个函数赋值给一个对象的属性,该行为也不会发生改变:

  var o = {prop: 37};
  function getProp() {
    return this.prop
  }
  o.f = getProp;
  
  console.log(o.f()); // 37

对象原型链中的this值

同样的,this仍然指向调用该函数的对象,尽管该函数位于该对象的原型链中:

  var o = {f: function() {return this.a + this.b;}};
  var p = Object.create(o);
  p.a = 1;
  p.b = 2;
  
  console.log(p.f()); //3

getter 或 setter 中的this

当函数作为属性的getter或者setter时,其中的this值指向该属性所在的对象:

  function sum() {
    return this.a + this.b + this.c
  }
  
  var o = {
    a: 1,
    b: 2,
    c: 3,
    get average() {
      return (this.a + this.b + this.c) / 3;
    }
  };
  Object.defineProperty(o, 'sum', {
    get: sum, enumerable: true, configurable: true
  });
  
  console.log(o.average, o.sum); // 2, 6

call方法 VS apply方法

call方法和apply方法都可以设置函数的this值,两者的第一个参数都是this值所指向的对象,区别在于call方法中的arguments是作为单个值传入fun.call(thisArg, arg1, arg2, ...),而apply方法中的arguments是作为数组传入func.apply(thisArg, [argsArray])

bind方法

ES5引入了Function.prototype.bind方法,调用f.bind(someObject)可以创建一个新的函数,该函数与f具有相同的函数体和作用域,但是新函数this值始终指向someObject。

  function f() {
    return this.a;
  }
  
  var g = f.bind({a: 'abc'});
  console.log(g()); // abc
  
  var h = g.bind({b: '123'}); // bind only works once
  console.log(h()); //abc 

注意到:通过bind方法获得的函数再次调用bind方法得到的新函数this值不会发生变化!

箭头函数

由于this值是自动获得的,以下hack的写法大家一定不陌生:

  {
    ...
    addAll: function addAll(pieces) {
      var self = this;
      _.each(pieces, function (piece) {
        self.add(piece);
      });
    },
    ...
  }

为了解决该问题,ES2015中引入了箭头函数语法糖,然而箭头函数的this值与一般函数的this值又有所区别,箭头函数的this值始终继承其外围作用域中的this值,在全局环境中将指向全局对象:

  // ES6
  {
    ...
    addAll: function addAll(pieces) {
      _.each(pieces, piece => this.add(piece));
    },
    ...
  } 

此处的addAll方法中的this值指向调用该方法的对象,而其内部的箭头函数的this值则继承自addAll方法的this值。

上一篇下一篇

猜你喜欢

热点阅读