React:在哪里扩展对象原型

Ahm*_*eki 8 javascript prototype reactjs create-react-app

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

String.prototype.someFunction = function () {
    //some code
}
Run Code Online (Sandbox Code Playgroud)

(您可能需要查看此问题以了解有关扩展对象原型的更多信息.)

是的我可以在组件旁边定义它并在其中使用它.但最好和最干净的方法是什么?

我应该把它写成一个class method或一个内部componentDidMount或其他东西?

编辑:

在React(或JavaScript)中扩展对象原型甚至是"OK"吗?

Der*_*ing 11

TLDR答案:无处可去!

- 细致的答案 -

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

在React(或JavaScript)中扩展对象原型甚至是"OK"吗?

在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())
Run Code Online (Sandbox Code Playgroud)

您将创建一个子类(仅适用于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?')
Run Code Online (Sandbox Code Playgroud)

这个子类在各方面都像内置String一样工作,当然除了你不能写像字符串文字这样的MyString文字.

我使用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及其生态系统的函数式编程原理.任何人都可以快速阅读和理解纯函数,因此使用它们来完成数据和状态转换,而不是依赖于修改全局对象等难以跟踪的黑客攻击.理解这个小小的黑客可能是可爱而微不足道的,但在项目中甚至做一次就会促进并鼓励自己和他人使用额外的快捷方式和反模式.

  • 我是一名专业人士,我一直这样做。它可以非常方便。 (2认同)