【问题标题】:Strange javascript toString() behaviour奇怪的javascript toString() 行为
【发布时间】:2020-01-09 04:44:03
【问题描述】:

我正在尝试使用 toString 将一个类临时输出到 DOM。 我有一些行为,我不明白覆盖的toString() 将始终输出初始状态。但是,如果使用外部函数(即 stateToString)甚至JSON.stringify,则更新后的状态会按我的预期输出。

以下是我尝试最小化重现这种行为的尝试。 重申一下,我的预期行为是让他们所有人最初输出:["initial"],他们会这样做。但是,当单击按钮时,toString() 输出不会更新,但其他两个会更新。

这似乎特别奇怪,因为stateToStringState.toString 似乎本质上是相同的函数,除了一个将状态作为接收器,另一个将状态作为参数。

如果有人能解释为什么会发生这种行为,我将不胜感激。

import React, { useReducer } from 'react';

class State { 
  constructor(xs) { this.xs = xs } 
  toString = () => `[${this.xs}]`
}

const stateToString = state => `[${state.xs}]`;

const reducer = (state, action) => ({
  ...state,
  xs: [...state.xs, action.x]
});

const App = () => {
  const [state, dispatch] = useReducer(reducer, new State(["initial"]));
  return (
    <div>
      <button onClick={() => dispatch({ x: Math.random() })}>click</button><br />
      toString:  {state.toString()}<br />
      print:     {stateToString(state)}<br />
      stringify: {JSON.stringify(state)}
    </div>
  );
};

export default App;

【问题讨论】:

    标签: javascript reactjs use-reducer


    【解决方案1】:

    你放在State上的toString方法绑定到状态的原始实例

    class State { 
      constructor(xs) { this.xs = xs } 
      toString = () => `[${this.xs}]` // Class field arrow function
    }
    

    那里的类字段意味着无论toString被调用的调用上下文是什么,它都会返回初始状态的this.xs。即使 reducer 更新了状态,状态的构造函数不会再次运行

    在以后调用App 时,会创建初始状态,然后通过一些操作对其进行更新,从而导致state 变量成为更新的对象,但它仍然有一个toString方法绑定到初始状态

    以下是 vanilla JS 中的行为示例:

    const obj = {
      val: 'val',
      toString: () => obj.val
    };
    
    const copiedObj = { ...obj, val: 'newVal' };
    console.log(copiedObj.toString());

    如果您分配了 function 而不是箭头函数,那么 toString 将使用 updated 状态的调用上下文来调用,因为它没有绑定到初始状态,所以它将使用更新状态的调用上下文进行调用,并正确检索xs

    toString = function () {
        return `[${this.xs}]`;
    }
    

    顺便说一句,你不能像

    那样使用普通的方法
    toString() {
        return `[${this.xs}]`;
    }
    

    因为在你的减速器中:

    const reducer = (state, action) => ({
        ...state,
        xs: [...state.xs, action.x]
    });
    

    spread syntax 只接受 enumerable own 属性。使用 method 语法(如 toString() {),该属性被放在 State prototype 上,而不是实际实例,因此它不会存在于最终的 state ,而将调用内置的Object.prototype.toString

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-20
      • 2011-07-28
      • 2012-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多