Chrome、Firefox 调试器未在 React 应用程序中显示“this”的正确值

dwj*_*ton 3 javascript browser debugging babeljs create-react-app

这是反应组件类中的一些代码(使用 CRA 2 搭建)

  click = () => {
    console.log(this, "hello");
    let x = 1 + 1; //This is just here to let chrome put a break point here. 
  }
Run Code Online (Sandbox Code Playgroud)

当此代码运行时,它会将组件对象打印到控制台。

但是 - 如果我将调试器附加到该点,Chrome (68) 和 Firefox (63) 都会将“this”显示为未定义。

这里发生了什么?

是否与用于将点击创建为类属性的 transform-class-properties babel 插件有关?

编辑: 是的,这似乎正是它的样子。

如果我们手动绑定方法,如:

  constructor() {
    super();
    this.click2 = this.click2.bind(this);
  }

  click2() {
    console.log(this, "hello");
    let x = 1 + 1;
  }
Run Code Online (Sandbox Code Playgroud)

然后它工作正常。

在任何情况下 - 有没有一种方便的方法来解决这个问题,所以我不必把所有这些绑定语句都放进去?

Old*_*Pro 5

在 CodeSandbox 上创建了一个示例,我认为它可以重现您的问题,但我不确定。如果没有,请创建您自己的示例。相关代码包含在下面。

在这个例子中,代码工作正常。如您所料,console.log(this, "hello")记录一个Square对象+“你好”。如果let y = 2 + 2在行上放置断点,Chrome 调试器将显示

this: undefined
x: 2
y: undefined
Run Code Online (Sandbox Code Playgroud)

当然,y是 undefined 因为let y语句还没有执行。x如预期的那样定义。this是未定义的,因为 React 和 Babel 在幕后跳了很多圈,而且this实际上是未定义的。如果this要从调试器访问,则需要使用_this. 事实上,即使您在 line 上放置了一个断点let y = 2 + 2,那也不是正在执行的实际源代码或实际断点所在的位置。您所看到的是源映射提供的便利,它允许您查看并在您编写的代码上设置断点,尽管实际运行的代码完全不同(Babel 等处理的结果)。

我写的代码是:

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null
    };
  }

  click = () => {
    console.log(this, "hello");
    let x = 1 + 1; //This is just here to let chrome put a break point here.
    let y = 2 + 2; //This is just here to let chrome put a break point here.
  };

  render() {
    return (
      <button className="square" onClick={this.click}>
        {this.props.value}
      </button>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

实际运行的代码是:

var Square =
/*#__PURE__*/
function (_React$Component) {
  (0, _inherits2.default)(Square, _React$Component);

  function Square(props) {
    var _this;

    (0, _classCallCheck2.default)(this, Square);
    _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Square).call(this, props));
    (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "click", function () {
      console.log((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "hello");
      var x = 1 + 1; //This is just here to let chrome put a break point here.

      var y = 2 + 2; //This is just here to let chrome put a break point here.
    });
    _this.state = {
      value: null
    };
    return _this;
  }

  (0, _createClass2.default)(Square, [{
    key: "render",
    value: function render() {
      return _react.default.createElement("button", {
        className: "square",
        onClick: this.click
      }, this.props.value);
    }
  }]);
  return Square;
}(_react.default.Component);
Run Code Online (Sandbox Code Playgroud)

由于 React.js 内部结构(特别是它包装事件的方式),在调用处理程序时this是未定义的。如果您查看调用堆栈,您会看到executeDispatch调用对象invokeGuardedCallbackAndCatchFirstError的显式值是undefinedcontext该值最终this是回调内部的值。React 和 Babel 在你编写代码时试图对你隐藏所有这些,但他们不能完全对调试器隐藏它,特别是关于this,所以在这种情况下,你必须去实际代码中查看是否需要参考要_this在调试器。