在Javascript中访问私有成员的更好方法

时间:2009-06-25 03:13:43

标签: javascript prototype

在Javascript的prototypical inheritance model上读了一下后,我改变了构建类的风格

var Some_Class = function() {
    this.public_method = function() {
    };
    (function() {
        // constructor
    }).call(this)
}

var Some_Class = function() {
    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
};

虽然我知道这是一个很好的做法,但我不允许从公共方法访问私有方法

var Some_Class = function() {
    var private_member = 'whatever';

    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
    return private_member; // not possible
};

阅读文章here(Closure创建的构造函数)后,我就出来了

var Some_Class = function() {
    var private_member = 'whatever',

    private_method = function(_some_value) {
        // private method implementation
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {
            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

然而,这样做的缺点是什么?!如果我想在公共方法中访问private member,还是有更好的方法吗?

5 个答案:

答案 0 :(得分:11)

我的回答是无答案:JavaScript中没有内置的private访问权限,但这可以,因为YAGNI。以下是我在代码中创建private成员的方法:

function Some_Class() {
    this._private_member = 'whatever';
}

Some_Class.prototype._private_method = function() {
};

这很好。当private的唯一真正目的是保护自己免受......自己时,跳过篮球并不值得。

(我说这花了很多时间自己玩弄关闭和原型制作的每一个排列,就像你一样,最后说“搞砸它,它不值得”。)

答案 1 :(得分:10)

使用函数范围变量和闭包来模拟私有变量/函数是javascript社区中一个成熟的习惯用法。如果该变量确实是私有的,我认为这种方法没有任何缺点(尽管有些人声称某些浏览器/主机上的高性能代码必须注意创建多少个闭包)。

在您的示例中,private_method(及其环境)在所有对象之间共享 - 因为您的public_method闭包仅在第一次构造对象时创建(并绑定到构造函数的prototype属性,该属性设置创建的对象的内部原型链) - 所以使用的private_method只是第一次创建的那个。

以下是一些示例代码,可帮助说明正在发生的事情:

  var global = 1;

  var Some_Class = function() {
    var private_method = 'whatever';
    var now = ++global;
    print("outer now: " + now );
    private_method = function(_some_value) {
        // private method implementation
        print("inner now: " + now);
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {

            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

new Some_Class().public_method(); // outer now: 2, inner now: 2
new Some_Class().public_method(); // outer now: 3, inner now: 2
new Some_Class().public_method(); // outer now: 4, inner now: 2

你确定这就是你想要的吗?

如果你的private_method不需要引用封闭对象的状态,那么我认为按照你的方式做事情没什么好处。

我通常做的事情(如果我必须使用'new'来创建我的对象)如下:

function MyClass() {
  var private_var = 1; 
  function private_func()
  {

  }
  this.public_func = function() 
  {
     // do something
     private_func();
  }
  this.public_var = 10;
}

var myObj = new MyClass();

这种方法的缺点是每次通过'new'构造对象时,都会重新创建所有闭包。但除非我的探查器告诉我这个设计选择需要优化,否则我更喜欢它的简洁性和清晰度。

此外,我也没有看到您的代码中有以下好处:

  (function() { }).call(this);  // call the constructor

为什么要在构造函数中创建单独的作用域?

答案 2 :(得分:1)

如果您还没有这样做,请查看此JavaScript Module Pattern,它允许您从公共函数中访问私有方法和变量等。

答案 3 :(得分:1)

回应John Kugelman:用javascript创建私有成员是不可能的。和它一起生活。即使您创建了这样的机箱:

function SomeClass() {

   var _private = 0;
   this.public_acessor = function() {return _private};
}

任何用户仍然可以写:

SomeClass._not_private_anymore = 1;
SomeClass.public_acessor = function () {return this._not_private_anymore}; 

最后,您不能相信任何公共成员与您声明的成员相同。如果有人要破坏你的代码,他会!另一个用户不会因为它有用而破坏你的代码。

答案 4 :(得分:0)

使用原型,而不仅仅是单身。问题是,当是子类的时候,我的子类无法访问私有