这更像是一个理论问题,而不是一个如何问题。我正在开发一个项目,在这个项目中,对象可以“区分”成几种不同的类型,所以我决定探索一些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/
答案 0 :(得分:4)
ModifiedConstructor
不是 OriginalConstructor
的副本,它是同一个功能。
eval
's algorithm中的第一条指令是:
如果Type( x )不是String,则返回 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
。