【问题标题】:Can you extend an object that has access to private properties with a function that can also access those private properties?你能用一个也可以访问这些私有属性的函数来扩展一个可以访问私有属性的对象吗?
【发布时间】:2011-08-28 22:24:21
【问题描述】:

我正在外壳内创建一个对象。外壳中还有对象的函数可以访问的私有属性 - 这可以按预期工作。

我的问题:我希望其他人能够使用他们自己的函数(来自不同上下文的函数)扩展我的对象,但这些函数也需要访问相同的私有属性 - 我无法找到一种使这项工作发挥作用的方法。

我尝试了 .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 函数,有什么方法可能对我的代码有害吗?它不执行该功能,所以我看不出如何 - 但也许我错过了什么?

【问题讨论】:

标签: javascript scope


【解决方案1】:

Javascript 没有“受保护”的类比。你要么变得超级私密,要么完全公开。从这里您可以选择:

  1. 重新考虑你的类设计,让子类只依赖于父类的公共接口。

  2. 将 getter 和 setter 函数添加到公共接口。不一定是最好的事情,因为您不妨将属性公开(除了最佳实践问题等)

  3. 只需使用公共属性即可。这是在 Javascript 中进行 OO 继承的“自然”方式,如果您使用诸如在名称开头添加下划线之类的做法,通常不会有问题。作为奖励,您可以使用原型继承功能(很高兴知道如何使用它而不是仅使用基于闭包的类)

    function Base(){
        this._priv = "Hello world"
    };
    Base.prototype = {
        fn: function(){
            console.log(this._priv);
        }
    }
    
    var obj2 = new Base();
    obj2.fn = function(){ ... }
    

【讨论】:

    【解决方案2】:

    我讨厌回答我自己的问题 - 似乎有点失礼 - 但我是生活。 (因为我今天叫醒法语?)

    所以,虽然我发现昨晚在编辑我的原始问题时提出的 eval() 解决方案确实 似乎 是一个有效的解决方案,并且正确使用 eval 来保留对象的新函数中的上下文,它远非完美。

    首先,它在 FF 中有效,但 IE 和 Chrome 似乎都讨厌它(那些是我尝试的下一个,在它们都失败后我放弃尝试其他的)。虽然我确信它可能可以跨浏览器工作,但这似乎很麻烦。

    其次,它确实为新函数提供了相当多的权力,而且当我更多地查看我的代码时,我确实喜欢控制这些添加到我的对象中的新函数可以访问什么的想法。

    第三,.eval() 通常很慢 - 事实证明 .apply()(通常更快)可能工作得很好。

    这是因为我昨晚在某个时候意识到,这个对象上的新函数不需要设置任何私有变量(至少,我相当肯定它们不会) - 并且 .apply() 有效可以将值传递给他们阅读。

    我确信它不仅仅是这 3 件事,但现在我想我将使用更多的“包装”解决方案 - 像这样:

    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() - 甚至可能在我最终决定采取哪个方向之前重新审视它的这种具体用法。 (特别是如果我能想到需要设置私有值的情况)

    感谢大家的意见!

    【讨论】:

    • 回答您自己的问题绝不是失礼——如果您的自我回答对未来的访问者有帮助,我们很高兴拥有它。如果您认为这确实是最佳解决方案,您甚至可以接受自己的答案。
    【解决方案3】:

    最快和最简单的解决方案是在任何所谓的私有属性前加上下划线 (_)。

    我个人喜欢将我的私有属性装入一个单独的对象中,然后放置在对象上,如下所示:

    obj.publicProp = 20;
    
    obj._.privateProp = true;
    

    不过我不会太担心,下划线基本上是私有的通用符号,因此使用该脚本的人会知道它是私有的,不应该被触及。或者,更好的是,将其从公共文档中删除;)

    还有其他方法,您可以使用它们来模拟“真正的”受保护变量,但它们并不是最好的,因为它们避免了垃圾收集,而且使用起来很笨重。

    【讨论】:

    • ._. 凝视着我的灵魂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    • 2013-05-28
    • 2014-08-17
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多