私有变量在javascript对象的实例之间共享

时间:2014-03-05 23:39:42

标签: javascript

我正在尝试使用Stefan Stoyanov的Javascript Patterns中描述的“揭示模块”模式(构造函数版本)。

我有一个简单的Point对象,它有两个私有变量_x和_y。当我尝试使用不同的_x和_y创建Point的多个实例时,所有实例看起来都指向同一个对象。它们具有相同的_x和_y变量值。

这是我工作的jsFiddle示例的链接,它演示了确切的问题。

http://jsfiddle.net/8dt2E/

那么我如何确保不共享私有变量,同时仍将它们保密(在构造函数中将它们设置为'this'使它们可以直接访问)?我相信我想做的事情是可能的,我是对的吗?

仅供参考我的代码:

var Point = (function() {
    // Trying to use the revealing module pattern, as described in the book Javascript Patterns by Stoyan Stefanov'

    // Private.  Should only be accessible externally by public methods.
    var _x, _y;

    // Constructor
    var Constr = function(x, y) {
        _x = x;
        _y = y;
    }

    var getX = function() {
        return _x;
    }
    var getY = function() {
        return _y;
    }

    var toString = function() {
        return getX() + ", " + getY();
    }

    // Prototype.  These are the public functions that are being "revealed"  
    Constr.prototype = {
        constructor: Point,
        getX: getX,
        getY: getY,
        toString: toString
    }

    return Constr;
})();

var pt1 = new Point(100, 100);
var pt2 = new Point(200, 200);
var pt3 = new Point(300, 300);
var pt4 = new Point(400, 400);

// Problem: Points all share the same private variables.  
alert("pt1: " + pt1);
alert("pt4: " + pt4);

3 个答案:

答案 0 :(得分:3)

您的私有变量是IIFE的一部分,因此它们将被创建一次,然后或多或少 static 到每个其他对象实例化。您需要在this对象内部设置Constr的属性。

或者,您可以在Constr()构造函数内部分配函数并使用普通var变量。这虽然有一些缺点......

  • 在每个函数调用上分配它们(原型上没有一次)
  • 如果你将它们分配给原型,那么你在每次调用时都会这样做
  • 可以混淆在构造函数中合并很多东西,我更喜欢它们作为一个轻量函数,但这是个人选择

revealing module pattern(免责声明:我自己的博客)旨在隐藏在外部世界中使用的某些方法和属性,但此模式不适用于对象实例这需要他们自己的实例数据。

答案 1 :(得分:2)

对于有类似问题的其他人;下面更新的代码现在符合我的私人变量外部无法访问的主要要求。

这是可能的,因为我将函数和变量定义为构造函数中的locals。但是,这也意味着每个实例都有自己的函数副本(内存使用效率低下)。

原型方法将确保实例之间只共享一个函数副本,但这使得无法访问不可访问的私有变量。如果有任何错误,请纠正我,我会更新,我很想知道这是否真的可行。

 var Point=(function() {

    // Constructor
    var Constr = function(x, y) {
        // Private
        var _x = x;
        var _y = y;

        var privateFunc=function(str) {

            alert('Private: ' + str + '  ' + _x);
        }

        // Public
        this.getX = function() {

            return _x;
        };

        this.getY = function() {
            return _y;
        };      

        this.toString = function() {
            return this.getX() + ", " + this.getY();
        };
    }


    // Prototype.  
    Constr.prototype = {
        constructor: Point
    }

    return Constr;
})();


var pt1 = new Point(100, 100);
var pt2 = new Point(200, 200);
var pt3 = new Point(300, 300);
var pt4 = new Point(400, 400);

alert("pt1: " + pt1);
alert("pt2: " + pt2);
alert("pt3.getX(): " + pt3.getX());
alert("pt4._y: " + pt4._y);
//alert(pt4.privateFunc('123'));

答案 2 :(得分:1)

你可以用技巧做你想要的(用原型函数访问私有变量)。

var Point = (function() {

// Private storage. Not accessible directly outside the closure
var reg = [];

// Constructor
var Constr = function(x, y) {
    var privates = {x:x, y:y};
    reg.push(privates);
    this._key = reg.length - 1;
}

var getX = function() {
    return reg[this._key].x;
}
var getY = function() {
    return reg[this._key].y;
}

var toString = function() {
    return this.getX() + ", " + this.getY();
}

Constr.prototype = {
    constructor: Point,
    getX: getX,
    getY: getY,
    toString: toString
}

return Constr;
})();

var pt1 = new Point(100, 100);
var pt2 = new Point(200, 200);
var pt3 = new Point(300, 300);
var pt4 = new Point(400, 400);

// Points all share the same accessors which look up the private registry via this._key
alert("pt1: " + pt1);
alert("pt4: " + pt4);

但也有缺点:

  • 即使注册表不是,_key仍然是公开的并且可以修改。
  • 当您的Point实例收集垃圾但内部存留在内存中时,可能会发生内存泄漏。