0

这更像是一个理论问题,而不是一个如何做的问题。我正在做一个项目,其中对象可以“区分”成几种不同的类型,所以我决定探索一些 Javascript 的动态特性,但有一件事情让我非常困惑:

OriginalConstructor = function() {this.value = 42;}
originalInstance = new OriginalConstructor();
ModifiedConstructor = eval(originalInstance.constructor);
ModifiedConstructor.prototype.addedFunction = function(x) {return this.value + x;}
modifiedInstance = new ModifiedConstructor();
document.write("modified: " + modifiedInstance.addedFunction(10));
document.write("<br>original: " + originalInstance.addedFunction(20));

为什么addedFunction一定要originalInstance,即使ModifiedConstructor被抄通过eval()?当然这两个构造函数不能有相同的引用,不是吗?

有没有办法在不影响已经从同一个构造函数实例化的其他对象的情况下修改一个对象(或未来的实例)?我知道还有其他方法可以解决这个问题,但我想更深入地了解 Javascript。感谢您提供的任何见解。

@Felix Kling:感谢您提供快速、清晰和完整的答案。出于某种原因,我认为构造函数属性是一个可以由 eval() 解析的字符串,所以现在我明白为什么这不起作用了。我仍然没有完全理解原型继承,但至少现在我知道我需要研究什么。谢谢!

编辑:我现在明白了。如果您来自经典 OOP 的背景,原型继承似乎很奇怪,但它在概念上更简单,更容易理解,而且在某些方面它实际上更强大。如果你想了解更多关于 Javascript 的原型继承,我强烈推荐这些文章:

http://javascript.crockford.com/prototypal.html

http://www.laktek.com/2011/02/02/understanding-prototypical-inheritance-in-javascript/

http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html

http://howtonode.org/prototypical-inheritance

此外,如果您需要这种灵活性,您可能需要考虑使用“实体系统”,它可以提供一些优点作为复杂继承层次结构的替代方案。大多数关于实体系统的文章都关注游戏开发,但我认为这种架构也可以用于其他应用程序。对于 OOP 程序员来说,这是一个非常陌生的概念,所以抛开你所知道的关于 OOP 的一切,更多地从关系数据库设计的角度来思考。看看这个:

http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/

4

1 回答 1

4

ModifiedConstructor 不是的副本OriginalConstructor,它是一个相同的功能。

eval的算法中的第一条指令是:

如果 Type( x ) 不是字符串,则返回x

即,您只需取回您传入的内容。OriginalConstructor === ModifiedConstructor产量true

有没有办法在不影响已经从同一个构造函数实例化的其他对象的情况下修改一个对象(或未来的实例)?

您可以通过原型继承:

ModifiedConstructor = function() {
    OriginalConstructor.apply(this, arguments);
};

ModifiedConstructor.prototype = Object.create(OriginalConstructor.prototype);
ModifiedConstructor.prototype.constructor = ModifiedConstructor;

现在您可以在ModifiedConstructor.prototype不影响由OriginalConstructor.

如果您只想防止已创建的实例被扩展,您可以只覆盖OriginalConstructor.prototype,但这不是一个干净的解决方案,并且还会破坏instanceOf现有实例。

于 2012-10-26T03:03:17.967 回答