简体   繁体   English

摩卡测试中以下js箭头功能中的“ this”指向什么?

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

What does this point here? 什么this位置呢?

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? 顺便说一句,这是很好的使用this在上面的代码如果同时this相同的对象(或多个)点?

UPDATE 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. 在您查询的两个位置中, this都是由Mocha绑定到内部Mocha对象的。 One thing this object allows you to do, for instance, is change Mocha's configuration. 例如,此对象允许您做的一件事就是更改Mocha的配置。 Like changing the timeout of asynchronous function with this.timeout(newValue) . 就像使用this.timeout(newValue)更改异步函数的超时一样。 It's not particularly useful in the example below, but Mocha will run it just fine. 在下面的示例中,它并不是特别有用,但是Mocha可以很好地运行它。 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. 请注意,如果要在afterEach回调中使用箭头函数,则无法访问Mocha为回调设置的this值。 ( this will have a value set in an outer scope.) this将在外部范围中设置一个值。)

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 . 我不建议this设置任意字段。 There's no telling when the field you set is going to clash with a field introduced by a newer version of Mocha. 无法确定您设置的字段何时会与较新版本的Mocha引入的字段发生冲突。 I've always been able instead to set a variable in the enclosing describe and use that: 我总是能够代替在封闭的describe设置变量并使用它:

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. 不论你得到{}这是因为封闭你的所有功能在控制台上console.log是箭头功能,正如我上面所说的,如果你用一个箭头功能,那么您将无法访问对象摩卡结合this是因为在这种情况下this从外部作用域获取,而不是从绑定到函数的值获取。 If all enclosing functions are arrow functions then this comes from the outermost scope and it has the value {} in the outermost scope. 如果所有封闭函数都是箭头函数,则this来自最外层范围,并且在最外层范围内具有值{}

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. 您收到的错误是因为您不能仅将Mocha分配给this的值转储到控制台,因为如错误消息所示,它是一个带有循环引用的结构。

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. 箭头函数在定义时绑定了“ this”上下文,但更重要的是您的问题。 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 } this现在指向包装对象{ a,b }

If you use an ES6 to ES5 ⚠ will replace this with undefined 如果使用ES6到ES5⚠将取代thisundefined

"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 };
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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