【问题标题】:How does technique for making a copy of a function works in JavaScript (Storybook example)制作函数副本的技术如何在 JavaScript 中工作(故事书示例)
【发布时间】:2020-11-28 20:14:56
【问题描述】:

Storybook recommends 复制函数的技术:

const Template = args => <Task {...args} />;
export const Default = Template.bind({});

它允许每个导出的故事设置自己的属性,但使用相同的实现。 我理解结果,但不明白为什么它必须将函数绑定到一个空对象{}

【问题讨论】:

    标签: javascript ecmascript-6 storybook


    【解决方案1】:

    您提供的链接中的完整相关代码是:

    import React from 'react';
    
    import Task from './Task';
    
    export default {
      component: Task,
      title: 'Task',
    };
    
    const Template = args => <Task {...args} />;
    
    export const Default = Template.bind({});
    Default.args = {
      task: {
        id: '1',
        title: 'Test Task',
        state: 'TASK_INBOX',
        updatedAt: new Date(2018, 0, 1, 9, 0),
      },
    };
    
    export const Pinned = Template.bind({});
    Pinned.args = {
      task: {
        ...Default.args.task,
        state: 'TASK_PINNED',
      },
    };
    

    使用Template.bind({}) 允许在每个副本和原始成员(此处未使用)上以不同方式定义额外成员,例如Default.args = {...}

    编辑

    正如链接中的文档所述:

    Template.bind({}) 是一种用于制作副本的standard JavaScript 技术 的一个功能。我们使用这种技术来允许每个导出的故事 设置自己的属性,但使用相同的实现。

    【讨论】:

    • 这个:Template.bind({}) is a standard JavaScript technique for making a copy of a function. 不正确。 bind 不复制函数。它创建了一个包装原始函数的函数。
    【解决方案2】:

    上面的代码 sn-p 在箭头函数上使用了bind()

    const Template = args => <Task {...args} />;
    export const Default = Template.bind({});
    

    在箭头函数上使用bind 根本不会修改箭头函数的行为,因为箭头函数的this 将始终是定义箭头函数的范围。

    MDN 建议不要在箭头函数MDN - Arrow function expressions: call, apply and bind 上使用bind

    调用、应用和绑定方法不适用于箭头函数——因为它们被设计为允许方法在不同的范围内执行——因为箭头函数基于范围建立“this”箭头函数是在其中定义的。

    const arrowFn = () => {
      console.log('this.foo:', this.foo);
    };
    
    window.foo = 'window.foo';
    const myObj = {
      foo: 'myObj.foo'
    };
    
    const boundFn = arrowFn.bind(myObj);
    
    arrowFn();  // 'window.foo'
    boundFn();  // 'window.foo'

    由于bind 不能修改箭头函数,bind 在上面的示例中唯一有用的事情是创建一个新的包装函数,它可以拥有自己的独特属性。

    因此,提供的示例中的代码:

    const Template = (...args) => {};
    const Default = Template.bind({});
    Default.args = {...};
    

    可以替换为:

    const Template = (...args) => {};
    Default = function () { Template(...arguments); }
    Default.args = {...};
    

    第二种模式的优点是不以非标准方式使用bind

    【讨论】:

    • 这不是真的,在任何肯定中:bind 不包含在传统函数中,所做的比较不正确,第二种模式不是更好:实际上是另一种解决方案(优化程度稍低),可能无法在所有情况下都按预期工作。
    • @emi - 感谢 cmets。我已经编辑了答案。即使原始示例“有效”,我仍然认为应避免在箭头函数上使用bind(如 MDN 中所述)。
    • I still submit that using bind on an arrow function should be avoided (as stated in MDN) 这只适用于函数使用this的情况,并非如此。
    • 注意:这个问题是针对Storybook 的,其中this 不是规范的一部分,bind 的使用方式有据可查。
    • @emi - 实际上,记录非标准模式不如以标准方式使用不同模式。
    猜你喜欢
    • 2011-07-08
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    相关资源
    最近更新 更多