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

Jef*_*y04 7 javascript prototype

在阅读了Javascript的原型继承模型后,我改变了构建类的风格

var Some_Class = function() {
    this.public_method = function() {
    };
    (function() {
        // constructor
    }).call(this)
}
Run Code Online (Sandbox Code Playgroud)

var Some_Class = function() {
    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
};
Run Code Online (Sandbox Code Playgroud)

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

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

    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
    return private_member; // not possible
};
Run Code Online (Sandbox Code Playgroud)

在阅读了这里的文章(Closure-created constructor)后,我就出来了

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)
}
Run Code Online (Sandbox Code Playgroud)

但是,这样做的缺点是什么?!或者,如果我想在公共方法中访问私有成员,是否有更好的方法?

Joh*_*ica 11

我的回答是没有答案:privateJavaScript中没有内置访问权限,但是没关系,因为YAGNI.以下是我private在代码中创建成员的方法:

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

Some_Class.prototype._private_method = function() {
};
Run Code Online (Sandbox Code Playgroud)

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

(我说这花了很多时间自己玩弄关闭和原型设计的每一个排列,就像你一样,最后说"拧它,它不值得".)


Fai*_*ali 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

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