私有JS函数,这是怎么回事

Private JS function, What is wrong with this?

本文关键字:怎么回事 JS 函数 私有      更新时间:2023-09-26
  1. 在构造函数中为对象编写公共函数有什么问题吗
  2. 在构造函数函数的原型链中添加函数有什么问题吗
  3. 替代方案
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.在对象的构造函数中为其编写公共函数有什么问题吗?

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

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之后创建的,并重新连接了原型。

原型上的函数不能访问以您创建它们的方式(在构造函数中)创建的"私有"函数。

3.替代方案?

这可能是一个太宽泛的问题,无法回答,但上面的规则应该可以帮助你决定如何进行。

但是,如果拥有实例的私有特性对您来说是一件重要的事情,那么您可以在获得函数重用的同时使用一种模式。我在这篇博客文章中详细介绍了这一点,但要点是:

在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之外的任何东西都不能轻易使用几乎私有的数据,因为属性名称不断更改。