小编典典

反应:在哪里扩展对象原型

reactjs

我使用create-react-app创建了一个纯React应用程序。我想扩展String该类并在一个或多个组件中使用它。例如:

String.prototype.someFunction = function () {
    //some code
}

是的,我可以在组件旁边定义它并在内部使用它。但是什么是最好最干净的方法?

我应该将其写为a class method还是内部componentDidMount还是其他?

编辑:

在React(或JavaScript)中扩展对象原型甚至“还行”吗?


阅读 272

收藏
2020-07-22

共1个答案

小编典典

TLDR答案:无处!

-微妙的答案-

我想做的是扩展纯JavaScript类,例如String类,这是javascript中非常常见的任务

在React(或JavaScript)中扩展对象原型甚至“还行”吗?

用JavaScript扩展/修改本机原型是一个有争议的主题,与您所说的相反,大多数专业开发人员都不经常这样做。在普遍的共识是,扩大本地JS的原型是要避免的编程反模式,因为它打破了封装和修改全局状态的原则。但是,与许多规则一样,可能很少有例外。例如:您正在从事一个不需要提高产品质量的玩具项目,您是唯一会接触该代码库的开发人员,否则您的代码将永远不会成为任何其他人的依赖。

如果您有充分的理由并且真的知道自己在做什么,并且完全了解修改运行时环境和依赖项的本机数据类型/行为的潜在后果,那么也许您会发现一些有效的用法这种做法的情况。但是很可能不是,或者至少不是很经常。几乎从未像现在这样。

如果您只是在追求便利性/语法糖,那么最好使用实用功能(例如lodash,下划线或ramda)并学习练习功能组合。但是,如果您确实致力于面向对象的范例,那么
您可能应该只是“子类化”本机数据类型,而不是修改它们

因此,与其像这样改变类的原型,不如说:

String.prototype.somethingStupid = function () {
  return [].map.call(this, function(letter) {
    if ((Math.random() * 1) > .5) return letter.toUpperCase()
    else return letter.toLowerCase()
  }).join('')
}

console.log('This is a silly string'.somethingStupid())

您将创建一个子类(仅适用于ES6类语法),如下所示:

class MyString extends String {
  constructor(x = '') {
    super(x)
    this.otherInstanceProp = ':)'
  }

  somethingStupid() {
    return [].map.call(this, function(letter) {
      if ((Math.random() * 1) > .5) return letter.toUpperCase()
      else return letter.toLowerCase()
    }).join('')
  }
}

const myStr = new MyString('This is a silly string')
console.log(myStr)
console.log(myStr.valueOf())
console.log(myStr.somethingStupid() + ', don\'t you think?')

该子类在所有方面都将像内置String一样工作,除了您当然不能编写MyString文字(如String文字)之外。

我使用create-react-
app创建了一个纯React应用程序。我想扩展String类,并在一个或多个组件中使用它。是的,我可以在组件旁边定义它,并在其中使用它。但是什么是最好最干净的方法?…我应该将其编写为类方法还是在componentDidMount或其他内容中?

由于修改内置的原型(通过String.prototype更改诸如之类的东西)会更改应用程序的全局状态,因此您几乎只可以肯定要在其他任何代码执行之前执行一次(因为您正在设置操作方式的全局状态)字符串在之后执行的所有代码中都起作用。因此,从React组件实例方法中更改内置原型没有多大意义。

如果您要去做肮脏的事,建议您为要修改的每种本机类型创建一个单独的模块,并将这些模块放置在src/lib/extend-built- ins/类似的位置,然后将import它们作为中的第一件事src/index.js。您无需导出任何内容。这样做import src/lib/extend-built- ins/String.js将执行代码,这将使您的全局状态发生变化。这样至少可以提供良好的组织,并确保在应用程序的其余代码运行之前完全修改了应用程序环境。这样,您可以在整个应用程序中使用扩展类型,而不必考虑从某个地方导入它们。

如果您打算使用子类化路线(class MyThing extends NativeThing),那么我建议您在类似的单独模块中类似地定义自定义类src/lib/native- subclasses/。但是在这种情况下,您将必须将import类构造函数放入要使用它们的任何/每个模块中。

但是,如果您要开发干净的,可测试的,可重构的代码,这些代码对于其他人和您将来的自我来说很容易理解,那么您就不应该这样做。相反,请考虑采用React及其生态系统的功能编程原理。任何人都可以快速阅读和理解纯函数,因此可以使用它们来完成数据和状态转换,而不必像修改全局对象那样依赖于难以追踪的黑客。理解这一个小技巧可能很可爱而且琐碎,但是即使在一个项目中进行一次也可以促进并鼓励您自己和他人使用其他快捷方式和反模式。

2020-07-22