我在机箱内创建一个对象。在机箱中还有对象的功能可以访问的私有属性 - 这可以按预期工作。
我的问题:我希望其他人能够使用自己的函数扩展我的对象(来自不同上下文的函数),但这些函数也需要访问相同的私有属性 - 而且我一直无法找到一种使这项工作成功的方法。
我尝试过.call的各种配置,并将其功能包装在一个新功能中。我觉得我已经接近一个解决方案,但刚刚做空了。
以下是一些准确反映我情况的简化示例代码:
//extension object
//fn2 can be any function, with any number of arguments, etc.
var obj1 = {};
obj1.fn2 = function (s1, s2){ console.log(priv); };
//actual object
var obj2 = (function (){
//private property
var priv = "hello world";
//return object
var obj3 = {};
//return object's native fn (works)
obj3.fn = function (s){ console.log(priv); };
//extension happens here - but is obviously not correct
obj3.fn2 = obj1.fn2;
//return object
return obj3;
})();
//try output
obj2.fn("goodbye world"); //works
obj2.fn2("goodbye world", "thx 4 teh phish"); //fails
任何见解都将受到赞赏。我完全明白,如果我想要的是不可能的 - 但它确实应该是:P
编辑:谢谢大家的回复。我完全理解,属性更容易作为公共访问,并且通常继承的对象将无法访问它们。但是,由于新函数被附加到原始对象,我不得不相信有一种方法可以使用原始上下文而不是创建新函数的上下文。
现在,我是第一个说eval是邪恶的 - 实际上,我以前从未使用它,甚至考虑过使用它。但是,我正在尝试一切我能想到的工作 - 我偶然发现了这个(看似)工作解决方案:
obj3.fn2 = eval(obj1.fn2.toString());
所以,如果我检查以确保obj1.fn2是一个typeof函数,这有什么办法可能对我的代码有害吗?它没有执行该功能,所以我看不清楚 - 但也许我错过了什么?
答案 0 :(得分:2)
Javascript没有“受保护”的模拟。你要么超级私人,要么完全公开。从这里您可以选择:
重新考虑您的类设计,并让子类仅依赖于父类的公共接口。
将getter和setter函数添加到公共接口。不一定是最好的事情,因为你可能会公开这些属性(除了最佳实践问题和诸如此类的东西)
只需使用公共属性即可。这是在Javascript中进行OO继承的“自然”方式,如果您使用诸如在名称的开头添加下划线之类的捐赠,通常不会出现问题。作为奖励,你可以使用原型继承功能(很高兴知道如何使用它而不是只使用基于闭包的类)
function Base(){
this._priv = "Hello world"
};
Base.prototype = {
fn: function(){
console.log(this._priv);
}
}
var obj2 = new Base();
obj2.fn = function(){ ... }
答案 1 :(得分:1)
我讨厌回答我自己的问题 - 看起来像是一个失礼的人 - 但是我很喜欢。 (因为我今天醒了法国人?)
所以,虽然我发现昨晚我在原始问题的编辑中提出的eval()解决方案似乎是一个有效的解决方案,并且正确使用eval来保留对象的新功能中的上下文,远非完美。
首先,它适用于FF,但IE和Chrome似乎都讨厌它(那些是我尝试的下一个,并且在它们都失败后我放弃了尝试其他人)。虽然我确信可能可以在浏览器中工作,但这似乎很麻烦。
其次,它确实为新函数提供了相当大的功能,当我更多地查看我的代码时,我确实喜欢控制添加到我的对象的这些新函数可以访问的想法。
第三,.eval()通常很慢 - 事实证明.apply()(通常更快)可能运行得很好。
这是因为我昨晚在某个时候意识到这个对象上没有新函数需要设置任何私有变量(至少,我相当肯定他们不会) - 和.apply()有效罚款通过值让他们阅读。
我确信除了这三件事之外还有更多的东西,但是现在我想我会选择更多的'包装'解决方案 - 就像这样:
var f = function (){
var fauxThis = {};
fauxThis.priv = priv;
obj1.fn2.apply(fauxThis, arguments);
};
obj3.fn2 = f;
//(To be placed where I had "obj3.fn2 = obj1.fn2;")
我现在当然愿意考虑在非常具体的情况下使用eval() - 甚至可能在我做出最终决定之前重新考虑它的具体用法。 (特别是如果我能想到需要设置私有值的情况)
感谢大家的投入!
答案 2 :(得分:0)
最快捷,最简单的解决方案是使用下划线(_)为任何所谓的私有属性添加前缀。
就个人而言,我喜欢将我的私有属性装入一个可放置在对象上的单个对象,如下所示:
obj.publicProp = 20;
obj._.privateProp = true;
我不会太担心它,但是下划线基本上是私有的通用符号,所以使用脚本的人会知道它是私有的,不应该被触及。或者,更好的是,将其从公共文档中删除;)
还有其他方法,您可以使用哪些方法模拟“真正的”受保护变量,但它们不是最好的,因为它们可以避免垃圾回收,而且使用起来很笨拙。