简体   繁体   中英

What does `this` point at in the following js arrow functions in mocha tests?

What does this point here?

const expect = require('chai').expect;
const sinon = require('sinon');

describe('test', () => {
  describe('test()', () => {
    afterEach(function _test() {
      this.xxx = undefined; // What does `this` point here?
    });
  });

  describe('test2()', () => {
    afterEach(function _test2() {
      this.yyy = undefined; // What does `this` point here?
    });
  });
});

By the way, it is good to use this in the above codes if both this (s) point at the same object?

UPDATE

Code

describe('test', () => {
  console.log(1, this);
  before(() => {
    console.log(2, this);
  });
  beforeEach( () => {
    console.log(3, this);
  });
  describe('going deeper', () => {
    console.log(4, this);
    beforeEach(() => {
      console.log(6, this);
    });
    return it('has increased someVal to 3', function() {
      assert.equal(1,1);
      //console.log(7, this);
    });
  });
});

output:

1 {}
4 {}


  test
2 {}
    going deeper
3 {}
6 {}
      ✓ has increased someVal to 3


  1 passing (4ms)

code (changed one arrow function to normal function):

describe('test', () => {
  console.log(1, this);
  before(() => {
    console.log(2, this);
  });
  beforeEach( () => {
    console.log(3, this);
  });
  describe('going deeper', () => {
    console.log(4, this);
    beforeEach(function() { // HERE
      console.log(6, this);
    });
    return it('has increased someVal to 3', function() {
      assert.equal(1,1);
      //console.log(7, this);
    });
  });
});

output:

1 {}
4 {}


  test
2 {}
    going deeper
3 {}
      1) "before each" hook for "has increased someVal to 3"


  0 passing (6ms)
  1 failing

  1) test going deeper "before each" hook for "has increased someVal to 3":
     TypeError: Converting circular structure to JSON
      at Object.stringify (native)
      at formatValue (util.js:352:36)
      at inspect (util.js:186:10)
      at exports.format (util.js:72:24)
      at Console.log (console.js:43:37)
      at Context.<anonymous> (test3.js:32:15)

In both locations you inquire about, this is bound by Mocha to an internal Mocha object. One thing this object allows you to do, for instance, is change Mocha's configuration. Like changing the timeout of asynchronous function with this.timeout(newValue) . It's not particularly useful in the example below, but Mocha will run it just fine. Eg:

describe('test', () => {
  describe('test()', () => {
    afterEach(function _test() {
      this.timeout(5000);
      this.xxx = undefined;
    });

    it("foo", () => {});
  });

  describe('test2()', () => {
    afterEach(function _test2() {
      this.timeout(5000);
      this.yyy = undefined;
    });

    it("foo", () => {});
  });
});

Note that if you were to use an arrow function for your afterEach callbacks, you could not access the value of this that Mocha sets for the callback. ( this will have a value set in an outer scope.)

By the way, it is good to use this in the above codes if both this(s) point at the same object?

I don't recommend setting arbitrary fields on this . There's no telling when the field you set is going to clash with a field introduced by a newer version of Mocha. I've always been able instead to set a variable in the enclosing describe and use that:

describe('test', () => {
    let something;

    beforeEach(function _test() {
        something = fetchATestFixtureFromSomewhere();
    });

    it("foo", () => {
        // use the variable something here.
    });
});

Regarding your update. Everywhere you get {} on the console that's because all functions enclosing your console.log are arrow functions and as I've said above, if you use an arrow function then you cannot access the object that Mocha binds to this because in such case this is taken from an outer scope instead of being taken from the value bound to the function. If all enclosing functions are arrow functions then this comes from the outermost scope and it has the value {} in the outermost scope.

The error you get is because you cannot just dump the value Mocha assigns to this to the console, because as the error message indicates, it is a structure with a circular reference in it.

This is a good question because it is something that is not addressed in a lot of arrow function tutorials.

Arrow functions have there "this" context bound at definition time, but more importantly your question. The this will inherit recursively.

describe('test', () => {                 // `this` is the global object
  describe('test()', () => {             // `this` is the global object
    afterEach(function _test() {        
      this.xxx = undefined;              // `this` is the global object
    });
  });

  describe('test2()', () => {            // `this` is the global object
    afterEach(function _test2() {        
      this.yyy = undefined;              // `this` is the global object
    });
  });
});

Here is an example

  const foo = ()=>{ console.log("foo is window?",this === window); const a = (input)=>{console.log("a is window?",this === window); this._=input }; const b = ()=> {console.log("b is window?",this === window);return this._} return { a,b } } const bar= foo() console.log(bar.b()) // undefined bar.a(5) console.log(bar.b()) // 5 console.log(window._) // 5 

if you change

const b = ()=> {console.log("b is window?",this === window);return this._} 

to

const b = function() {console.log("b is window?",this === window);return this._} 

the this now points to the wrapping Object { a,b }

If you use an ES6 to ES5 ⚠ will replace this with undefined

"use strict"; // https://es6console.com/

var foo = function foo() {
    console.log("foo is window?", undefined === window);
    var a = function a(input) {
        console.log("a is window?", undefined === window);undefined._ = input;
    };
    var b = function b() {
        console.log("b is window?", undefined === window);return undefined._;
    };
    return { a: a, b: b };
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM