私有JS函数,这有什么问题?

时间:2014-09-17 20:50:20

标签: javascript javascript-objects

  1. 在构造函数中为对象编写公共函数有什么问题吗?
  2. 在构造函数中添加函数到原型链是否有什么问题?
  3. 替代方案?
  4. var obgect = function (constructorOptions) {
        var privateFunction1 = function (v1) {
            return 'You said: ' + v1;
        };
        this.willHaveAccessToPrivate = function () {
            return 'This function will have access to privateFunction1(), but will I be on prototype chain?';
        };
        obgect.prototype.anotherPublicFunction = function () {
            var s = privateFunction1('I have access to you.');
            return 'Adding on prototype from within the constructor.';
        };
    };
    obgect.prototype = new Object();
    obgect.prototype.outsidePublicFunction = function () {
        var s = privateFunction1('I will fail here because you are not accessible.');
        return 'Standard practice';
    };
    var instance = new obgect({
        'gurusWanted': true,
            'hurtsMyHead': true,
            'discouragesMe': false
    });
    var outside = instance.outsidePublicFunction(); // will fail here.
    var anotherInside = instance.anotherPublicFunction(); // will work!
    

1 个答案:

答案 0 :(得分:4)

  

1。在构造函数中为对象编写公共函数有什么问题吗?

不,这是相当普遍的做法。它确实意味着每个实例都获得了每个函数的自己的副本,这可能会对内存产生一些影响,但除非您创建了数千个不一定存在的问题。你必须知道你正在做它。

  

2。在构造函数中添加函数到原型链是否有什么问题?

,很棒的时间。它会在实例之间创建串扰,因为之前创建的实例将最终使用由以后创建的实例分配给原型的函数。非常非常需要避免的事情。考虑这个更简单的例子:

function Example(data) {
    var privateData = data;
    Example.prototype.doSomethingWithPrivateData = function() {
        console.log(privateData);
    };
}

var e1 = new Example(1);
e1.doSomethingWithPrivateData(); // "1"
var e2 = new Example(2);
e2.doSomethingWithPrivateData(); // "2"

到目前为止,这么好,对吗?的 可是:

e1.doSomethingWithPrivateData(); // "2"

糟糕! e1现在正在使用e2的私人数据,因为e2是在e1之后创建并重新布线原型的。

原型上的功能无法访问" private"函数创建的方式是你创建它们(在构造函数中)。

  

3。替代方案?

这个问题可能过于宽泛,但上述规则可以帮助您决定如何继续。

但是如果拥有实例的私有功能对你来说很重要,那么你可以使用一种模式,同时仍然可以重用函数。我详细说明了in this blog post,但这里是要点:

在ES6中,我们将拥有"私有Name个对象"它可以用作属性键,因此您可以将数据存储在无法访问的实例中,除非您有特殊的Name对象。现在,我们无法在ES5中执行此操作,但我们可以通过使用返回半随机名称的Name函数来实现,例如:

var Name = function() {
    var used = {};

    function Name() {
        var length, str;

        do {
            length = 5 + Math.floor(Math.random() * 10);
            str = "_";
            while (length--) {
                str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
            }
        }
        while (used[str]);
        used[str] = true;
        return new String(str); // Since this is called via `new`, we have to return an object to override the default
    }

    return Name;
}();

然后在这里我们如何(几乎)私人成员使用它:

// Nearly-private properties
// ***No `import` here (once the final form is determined, we'll probably be able to feature test for it)
var Foo = (function() {
    // Create a random string as our private property key
    var nifty = new Name();

    // Our constructor    
    function Foo() {
        // We can just assign here as normal
        this[nifty] = 42;
    }

    // ***On ES5, make the property non-enumerable
    // (that's the default for properties created with
    // Object.defineProperty)
    if (Object.defineProperty) { // Only needed for ES3-compatibility
        Object.defineProperty(Foo.prototype, nifty, {
            writable: true
        });
    }
    // ***End change

    // Methods shared by all Foo instances
    Foo.prototype.method1 = function() {
        // This method has access to `nifty`, because it
        // closes over the private key
        console.log("Truly private nifty info: " + this[nifty]);
    };
    Foo.prototype.method2 = function() {
        // Also has access, for the same reason
        console.log("Truly private nifty info: " + this[nifty]);
    };

    return Foo;
})();

var f = new Foo();
f.method1(); // Can use nifty!
f.method2(); // Can too! :-)
// Both `method1` and `method2` are *reused* by all `Foo` objects

Foo之外的任何内容都不能轻易使用近乎私密的数据,因为属性名称不断变化。