JavaScript 中制作函数副本的技术如何工作(Storybook 示例)

How does technique for making a copy of a function works in JavaScript (Storybook example)

Storybook recommends 复制函数的技巧:

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

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

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

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 = {...},在每个副本和原始版本(此处未使用)上有不同的定义。

编辑

正如 link 的文档中所说:

Template.bind({}) is a standard JavaScript technique for making a copy of a function. We use this technique to allow each exported story to set its own properties, but use the same implementation.

上面的代码片段在箭头函数上使用了 bind()

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

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

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

The call, apply and bind methods are NOT suitable for Arrow functions -- as they were designed to allow methods to execute within different scopes -- because Arrow functions establish "this" based on the scope the Arrow function is defined within.

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