【问题标题】:Javascript binding Higher-order function with input onchange not workingJavascript绑定输入onchange的高阶函数不起作用
【发布时间】:2021-01-18 05:18:21
【问题描述】:

我的目标是调用带有字符串参数的函数,调用函数将返回一个函数,该函数将从 html 输入对象接收事件对象,我想在第二个函数中使用字符串参数。

const person = {
  name:'',
  age:''
};

const regForm = (field) => {
  console.log('field : ', field);

  return event => {
    person[field]=event.target.value;
    document.getElementById("demo").innerHTML = JSON.stringify(person);
  }
};
<input onchange="regForm('name')"/>
<input onchange="regForm('age')"/>
<p id="demo"></p>

【问题讨论】:

  • 每次regForm 被调用时,它都会返回一个匿名箭头函数表达式。不会发生其他任何事情。

标签: javascript html dom events


【解决方案1】:

为了接近 OP 可能希望实现的目标,应该将代码分解为状态更改处理任务(可能是渲染任务)和侦听器初始化任务...

const person = {
  name:'',
  age:''
};

function renderPersonStateChange(personReference, key, value) {
  personReference[key] = value;

  document.body.querySelector('#demo').textContent = JSON.stringify(personReference);
}
function handleTextInputStateChange(evt) {
  const elm = evt.currentTarget;
  const key = elm.name;

  renderPersonStateChange(person, key, elm.value);
}

// initialize event listeners
document.body.querySelectorAll('input').forEach(elm =>
  elm.addEventListener('change', handleTextInputStateChange, false)
);
<input name='name' placeholder="enter person's name"/>
<input name='age' placeholder="enter person's age"/>
<p>
  <code>
    <pre id="demo">
    </pre>
  </code>
</p>

如果希望bind 引用的状态应该改变,那么上面的代码会稍微改变(仅用于更改处理程序和事件初始化部分)向...

const person = {
  name:'',
  age:''
};

function renderPersonStateChange(personReference, key, value) {
  personReference[key] = value;

  document.body.querySelector('#demo').textContent = JSON.stringify(personReference);
}
function handleStateChangeForBoundPerson(evt) {
  const personReference = this;

  const elm = evt.currentTarget;
  const key = elm.name;

  renderPersonStateChange(personReference, key, elm.value);
}

// initialize event listeners
document.body.querySelectorAll('input').forEach(elm =>
  elm.addEventListener('change', handleStateChangeForBoundPerson.bind(person), false)
);
<input name='name' placeholder="enter person's name"/>
<input name='age' placeholder="enter person's age"/>
<p>
  <code>
    <pre id="demo">
    </pre>
  </code>
</p>

【讨论】:

    【解决方案2】:

    问题是您的onchange 属性当前具有基于字符串的值,并且在触发更改事件时它实际上是evald。正如@PeterSeliger cmets,regForm 只是返回一个函数。

    regForm 可以返回任何东西,因此默认的更改处理程序不会对您的答案做出任何假设。您可能期望返回的函数会与事件一起被调用,但默认处理程序只是丢弃该值。

    一种解决方案是使用 JavaScript 的 onchange 属性,而不是 HTML 的 onchange 属性 -

    const person = {
      name:'',
      age:''
    }
      
    const regForm = field => event =>
      person[field] = event.target.value
    
    const form =
      document.forms.sample
      
    form.name.onchange = regForm("name")
    form.age.onchange = regForm("age")
    form.onsubmit = event => {
      event.preventDefault()
      console.log("Submitted", JSON.stringify(person))
    }
    <form id="sample">
      <input name="name" placeholder="enter your name" />
      <input name="age" placeholder="enter your age" />
      <input type="submit" />
    </form>

    由于您熟悉事件委托,即event.target,您可以删除额外的重复项。看起来regForm 有点消失了! -

    const data =
      {}
    
    const form =
      document.forms.sample
    
    form.onchange = event =>
      data[event.target.name] = event.target.value
      
    form.onsubmit = event => {
      event.preventDefault()
      console.log("Submitted", JSON.stringify(data))
    }
    <form id="sample">
      <input name="name" placeholder="enter your name"><br>
      <input name="age" placeholder="enter your age"><br>
      <input name="foo" placeholder="enter your foo"><br>
      <input name="bar" placeholder="enter your bar"><br>
      <input type="submit" />
    </form>

    输出

    Submitted {"name":"1","age":"2","foo":"3","bar":"4"}
    

    将其他函数作为输入和/或将其他函数作为输出返回的函数称为高阶函数。有各种各样的术语和技术来处理它们。相关阅读见What do multiple arrow functions mean?

    const preventDefault = f => event =>
      ( event.preventDefault()
      , f(event)
      )
      
    const logKeypress = event =>
      console.log(event.which)
      
    document
      .querySelector('input[name=foo]')
      .addEventListener('keydown', preventDefault(logKeypress))
    &lt;input name="foo" placeholder="type here to see ascii codes" size="50"&gt;

    【讨论】:

      猜你喜欢
      • 2011-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      相关资源
      最近更新 更多