将函数附加到 JavaScript 对象文字的 __proto__ 属性 是个好主意吗?
Is it ever a good idea to append functions to a JavaScript Object Literal's __proto__ property?
我有一个对象字面量:
var tasks = {};
那个我基本上是这样加东西的:
function addTask(task) {
tasks[task.id] = task
}
我想修改它以便我可以在每个任务上调用 start
函数。所以:
var tasks = {};
tasks.__proto__.start = function(key) {
// do stuff with this[key]
}
function addTask(task) {
tasks[task.id] = task
tasks.start(task.id)
}
我听说最好避免使用 proto 对象,它会减慢执行速度。但是我不是重新分配它,而是附加到它。
是否有更好的替代方案?
实际上没有必要为此使用原型。您不会创建许多需要在更高级别抽象的通用功能的实例,您只需在 tasks
对象上添加一个方法即可。
const tasks = {
start(key) {
const task = this[key]
// do stuff with task
}
}
// example call
tasks.start('123');
如果您想确保与现有密钥不冲突,可以改用 Symbol。
const startSymbol = Symbol('start');
const tasks = {
[startSymbol](key) {
const task = this[key]
// do stuff with task
}
}
// example call
tasks[startSymbol]('123');
您也可以只使用一个独立的函数来执行此操作,类似于您的 addTask
函数:
function start(tasks, key) {
const task = tasks[key]
// do stuff with task
}
// example call
start(tasks, '123')
拥有这个独立的功能可能会更好,因为您不必担心任务键和方法名称之间的冲突。
您还可以创建一个包装器对象来执行此分离:
const taskManager = {
tasks: {} // map of key to task
// methods
add(task) {
this.tasks[task.id] = task;
this.start(task.id);
}
start(key) {
const task = this.tasks[key];
// do stuff with task
}
}
// example usage
taskManager.start('123')
这种方法的优点是您的 tasks
被封装在一个对其进行操作的容器中,限制了 tasks
应该使用的范围并使其更加清晰(建议程序员) 哪些功能是要在任务上使用的。
如果您计划拥有多个任务管理器,那么在这里使用原型可能有意义:
class TaskManager {
constructor() {
this.tasks = {} // map of key to task
}
// methods
add(task) {
this.tasks[task.id] = task;
this.start(task.id);
}
start(key) {
const task = this.tasks[key];
// do stuff with task
}
}
// example usage
new TaskManager().start('123')
从性能和浏览器兼容性的角度来看,这都不是一个好主意。
请参阅来自 mozilla's documentation 的这些警告:
Warning: Changing the [[Prototype]] of an object is, by the nature of
how modern JavaScript engines optimize property accesses, a very slow
operation, in every browser and JavaScript engine. The effects on
performance of altering inheritance are subtle and far-flung, and are
not limited to simply the time spent in obj.proto = ... statement,
but may extend to any code that has access to any object whose
[[Prototype]] has been altered. If you care about performance you
should avoid setting the [[Prototype]] of an object. Instead, create a
new object with the desired [[Prototype]] using Object.create().
--
Warning: While Object.prototype.proto is supported today in most
browsers, its existence and exact behavior has only been standardized
in the ECMAScript 2015 specification as a legacy feature to ensure
compatibility for web browsers. For better support, it is recommended
that only Object.getPrototypeOf() be used instead.
我有一个对象字面量:
var tasks = {};
那个我基本上是这样加东西的:
function addTask(task) {
tasks[task.id] = task
}
我想修改它以便我可以在每个任务上调用 start
函数。所以:
var tasks = {};
tasks.__proto__.start = function(key) {
// do stuff with this[key]
}
function addTask(task) {
tasks[task.id] = task
tasks.start(task.id)
}
我听说最好避免使用 proto 对象,它会减慢执行速度。但是我不是重新分配它,而是附加到它。
是否有更好的替代方案?
实际上没有必要为此使用原型。您不会创建许多需要在更高级别抽象的通用功能的实例,您只需在 tasks
对象上添加一个方法即可。
const tasks = {
start(key) {
const task = this[key]
// do stuff with task
}
}
// example call
tasks.start('123');
如果您想确保与现有密钥不冲突,可以改用 Symbol。
const startSymbol = Symbol('start');
const tasks = {
[startSymbol](key) {
const task = this[key]
// do stuff with task
}
}
// example call
tasks[startSymbol]('123');
您也可以只使用一个独立的函数来执行此操作,类似于您的 addTask
函数:
function start(tasks, key) {
const task = tasks[key]
// do stuff with task
}
// example call
start(tasks, '123')
拥有这个独立的功能可能会更好,因为您不必担心任务键和方法名称之间的冲突。
您还可以创建一个包装器对象来执行此分离:
const taskManager = {
tasks: {} // map of key to task
// methods
add(task) {
this.tasks[task.id] = task;
this.start(task.id);
}
start(key) {
const task = this.tasks[key];
// do stuff with task
}
}
// example usage
taskManager.start('123')
这种方法的优点是您的 tasks
被封装在一个对其进行操作的容器中,限制了 tasks
应该使用的范围并使其更加清晰(建议程序员) 哪些功能是要在任务上使用的。
如果您计划拥有多个任务管理器,那么在这里使用原型可能有意义:
class TaskManager {
constructor() {
this.tasks = {} // map of key to task
}
// methods
add(task) {
this.tasks[task.id] = task;
this.start(task.id);
}
start(key) {
const task = this.tasks[key];
// do stuff with task
}
}
// example usage
new TaskManager().start('123')
从性能和浏览器兼容性的角度来看,这都不是一个好主意。
请参阅来自 mozilla's documentation 的这些警告:
Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in obj.proto = ... statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().
--
Warning: While Object.prototype.proto is supported today in most browsers, its existence and exact behavior has only been standardized in the ECMAScript 2015 specification as a legacy feature to ensure compatibility for web browsers. For better support, it is recommended that only Object.getPrototypeOf() be used instead.