Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/451.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
原型上的Javascript私有成员_Javascript_Prototype_Private - Fatal编程技术网

原型上的Javascript私有成员

原型上的Javascript私有成员,javascript,prototype,private,Javascript,Prototype,Private,我试着弄明白这有没有可能。以下是代码: a=function(text) { var b=text; if (!arguments.callee.prototype.get) arguments.callee.prototype.get=function() { return b; } else alert('already created!'); } var c=new a("test"); // creates

我试着弄明白这有没有可能。以下是代码:

a=function(text)
{
   var b=text;
   if (!arguments.callee.prototype.get)
      arguments.callee.prototype.get=function()
    {
         return b;
    }
    else
      alert('already created!');
}

var c=new a("test");  // creates prototype instance of getter
var d=new a("ojoj");  // alerts already created
alert(c.get())        // alerts test 
alert(d.get())        // alerts test from context of creating prototype function :(
正如你所见,我试图创建原型getter。为了什么?如果你写这样的东西:

a=function(text)
{
    var b=text;
    this.getText=function(){ return b}
}
。。。一切都会好起来的。。但事实上,每次我创建object时,我都会创建使用内存的getText函数。我想在内存中有一个原型函数,可以做同样的事情。。。有什么想法吗

编辑:

我尝试了克里斯托夫给出的解决方案,似乎这是目前唯一已知的解决方案。从上下文中检索值需要记住id信息,但整个想法对我来说很好:)id只是需要记住的一件事,其他所有东西都可以在内存中存储一次。事实上,你可以通过这种方式存储很多私人成员,并且在任何时候只使用一个id。实际上,这让我很满意:)(除非有人有更好的想法)


原型上的方法无法访问javascript中存在的“私有”成员;您需要某种特权访问器。由于您正在声明
get
,它可以从词汇上查看
b
,因此它将始终返回创建时的
b

JavaScript传统上不提供属性隐藏机制(“私有成员”)

由于JavaScript的作用域是词汇性的,所以您可以通过使用构造函数函数作为“私有成员”上的闭包并在构造函数中定义方法,在每个对象级别上始终模拟这种情况,但这对构造函数的prototype属性中定义的方法不起作用

当然,有办法解决这个问题,但我不推荐:

Foo = (function() {
    var store = {}, guid = 0;

    function Foo() {
        this.__guid = ++guid;
        store[guid] = { bar : 'baz' };
    }

    Foo.prototype.getBar = function() {
        var privates = store[this.__guid];
        return privates.bar;
    };

    Foo.prototype.destroy = function() {
        delete store[this.__guid];
    };

    return Foo;
})();
这将把“私有”属性存储在与
Foo
实例分离的另一个对象中。确保在处理完对象后调用
destroy()
:否则,您刚刚创建了内存泄漏


编辑2015-12-01:ECMAScript 6使不需要手动销毁对象的改进型成为可能,例如使用a或最好是a,完全避免了外部存储的需要:

var Foo = (function() {
    var bar = Symbol('bar');

    function Foo() {
        this[bar] = 'baz';
    }

    Foo.prototype.getBar = function() {
        return this[bar];
    };

    return Foo;
})();

在受到Christoph工作的巨大启发后,我提出了一个稍微修改的概念,提供了一些增强功能。同样,这个解决方案很有趣,但不一定推荐。这些改进包括:

  • 不再需要在构造函数中执行任何设置
  • 删除了在实例上存储公共GUID的需要
  • 添加了一些语法糖
本质上,这里的技巧是使用实例对象本身作为访问相关私有对象的密钥。对于普通对象,这通常是不可能的,因为它们的键必须是字符串。然而,我能够通过表达式
({}===={})
返回
false
来实现这一点。换句话说,比较运算符可以区分唯一对象实例之间的差异

长话短说,我们可以使用两个数组来维护实例及其关联的私有对象:

Foo = (function() {
    var instances = [], privates = [];

    // private object accessor function
    function _(instance) {
        var index = instances.indexOf(instance), privateObj;

        if(index == -1) {
            // Lazily associate instance with a new private object
            instances.push(instance);
            privates.push(privateObj = {});
        }
        else {
            // A privateObject has already been created, so grab that
            privateObj = privates[index];
        }
        return privateObj;
    }

    function Foo() {
        _(this).bar = "This is a private bar!";
    }

    Foo.prototype.getBar = function() {
        return _(this).bar;
    };

    return Foo;
})();
您会注意到上面的
\uu
函数。这是用于获取私有对象的访问器函数。它工作缓慢,因此如果您使用新实例调用它,它将动态创建一个新的私有对象

如果您不想为每个类复制
\uu
代码,可以通过将其包装到工厂函数中来解决此问题:

function createPrivateStore() {
    var instances = [], privates = [];

    return function (instance) {
        // Same implementation as example above ...
    };
}
现在,您可以为每个类将其缩减为一行:

var _ = createPrivateStore();

同样,使用此解决方案时必须非常小心,因为如果不在必要时实现并调用销毁函数,它可能会造成内存泄漏。

我创建了一个新库,用于在原型链上启用私有方法。

例如:

var MyObject = (function () {

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method, using (_)
    _private: function () {
      console.log('PRIVATE method has been called');
    }
  }

  return protect(MyObject);

})();

// Create an instance of the object
var mo = new MyObject();

// Call its methods
mo.public(); // Pass
mo._private(); // Fail

就我个人而言,我并不真正喜欢带有guid的解决方案,因为它迫使开发人员在存储之外声明它,并在构造函数中增加它。在大型javascript应用程序中,开发人员可能会忘记这样做,这很容易出错

我非常喜欢Peter的答案,因为您可以使用上下文访问私有成员(这一点)。但有一件事让我非常困扰,那就是访问私有成员是在一个o(n)复杂的环境中完成的。实际上,在数组中查找对象的索引是一种线性算法。假设您想使用这个模式来创建一个10000次的对象。然后,每次要访问私有成员时,您可能会遍历10000个实例

为了以o(1)复杂度访问私有存储,除了使用guid之外,没有其他方法。但为了不必担心guid声明和增量,也为了使用上下文访问私有存储,我修改了Peters factory模式,如下所示:

createPrivateStore = function () {
var privates = {}, guid = 0;

return function (instance) {
    if (instance.__ajxguid__ === undefined) {
        // Lazily associate instance with a new private object
        var private_obj = {};
        instance.__ajxguid__ = ++guid;
        privates[instance.__ajxguid__] = private_obj;
        return private_obj;
    }

    return privates[instance.__ajxguid__];
}
}


这里的诀窍在于考虑尚未处理<强> AjxGuID属性的对象。实际上,在第一次访问存储之前可以手动设置属性,但我认为没有神奇的解决方案。

随着现代浏览器采用了一些ES6技术,您可以使用
WeakMap
来解决GUID问题。这适用于IE11及以上版本:

// Scope private vars inside an IIFE
var Foo = (function() { 
    // Store all the Foos, and garbage-collect them automatically
    var fooMap = new WeakMap();

    var Foo = function(txt) { 
        var privateMethod = function() { 
            console.log(txt); 
        };
        // Store this Foo in the WeakMap
        fooMap.set(this, {privateMethod: privateMethod}); 
    } 

    Foo.prototype = Object.create(Object.prototype); 
    Foo.prototype.public = function() { 
        fooMap.get(this).p(); 
     } 
     return Foo; 
 }());

 var foo1 = new Foo("This is foo1's private method");
 var foo2 = new Foo("This is foo2's private method");
 foo1.public(); // "This is foo1's private method"
 foo2.public(); // "This is foo2's private method"

WeakMap
不会在任何
Foo
被删除或超出范围后存储对它的引用,而且因为它使用对象作为键,所以您不需要将guid附加到您的对象。

我认为真正的隐私被高估了。虚拟隐私是所需要的一切。我认为使用_privateIdentifier是朝着正确的方向迈出的一步,但还远远不够,因为您仍然会看到intellisense弹出窗口中所有_privateIdentifier的列表。更进一步更好的步骤是在prototype和/或constructor函数中创建一个对象,用于将虚拟私有字段和方法隔离到看不见的地方,如下所示:

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method tucked away inside a nested privacy object called x
    x: {
      private: function () {
        console.log('PRIVATE method has been called');
      }
    },

  }

// Create an instance of the object
var mo = new MyObject(); 
现在,当编码器键入“mo”时,intellisense将只显示公共函数和“x”。所以所有的私人成员
  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method tucked away inside a nested privacy object called x
    x: {
      private: function () {
        console.log('PRIVATE method has been called');
      }
    },

  }

// Create an instance of the object
var mo = new MyObject(); 
const Immutable = function ( val ) {
    let _val = val;

    this.$ = {
        _resolve: function () {
            return _val;
        }
    };
};
Immutable.prototype = {
    resolve: function () {
        return this.$._resolve();
    }
};