要创建一个带有公共方法的JavaScript类,我可以这样做:

function Restaurant() {}

Restaurant.prototype.buy_food = function(){
   // something here
}

Restaurant.prototype.use_restroom = function(){
   // something here
}

这样,我类的用户就可以:

var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();

如何创建一个私有方法,可以由buy_food和use_restroom方法调用,但不能由类的用户外部调用?

换句话说,我希望我的方法实现能够做到:

Restaurant.prototype.use_restroom = function() {
   this.private_stuff();
}

但这是行不通的:

var r = new Restaurant();
r.private_stuff();

如何将private_stuff定义为私有方法,使两者都成立?

我读过Doug Crockford的文章几次,但它似乎不像“私有”方法可以被公共方法调用,而“特权”方法可以被外部调用。


当前回答

你可以像这样模拟私有方法:

function Restaurant() {
}

Restaurant.prototype = (function() {
    var private_stuff = function() {
        // Private code here
    };

    return {

        constructor:Restaurant,

        use_restroom:function() {
            private_stuff();
        }

    };
})();

var r = new Restaurant();

// This will work:
r.use_restroom();

// This will cause an error:
r.private_stuff();

更多关于此技术的信息,请访问:http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html

其他回答

下面是我创建的类,用来理解Douglas Crockford在他的网站Private Members in JavaScript中的建议

function Employee(id, name) { //Constructor
    //Public member variables
    this.id = id;
    this.name = name;
    //Private member variables
    var fName;
    var lName;
    var that = this;
    //By convention, we create a private variable 'that'. This is used to     
    //make the object available to the private methods. 

    //Private function
    function setFName(pfname) {
        fName = pfname;
        alert('setFName called');
    }
    //Privileged function
    this.setLName = function (plName, pfname) {
        lName = plName;  //Has access to private variables
        setFName(pfname); //Has access to private function
        alert('setLName called ' + this.id); //Has access to member variables
    }
    //Another privileged member has access to both member variables and private variables
    //Note access of this.dataOfBirth created by public member setDateOfBirth
    this.toString = function () {
        return 'toString called ' + this.id + ' ' + this.name + ' ' + fName + ' ' + lName + ' ' + this.dataOfBirth; 
    }
}
//Public function has access to member variable and can create on too but does not have access to private variable
Employee.prototype.setDateOfBirth = function (dob) {
    alert('setDateOfBirth called ' + this.id);
    this.dataOfBirth = dob;   //Creates new public member note this is accessed by toString
    //alert(fName); //Does not have access to private member
}
$(document).ready()
{
    var employee = new Employee(5, 'Shyam'); //Create a new object and initialize it with constructor
    employee.setLName('Bhaskar', 'Ram');  //Call privileged function
    employee.setDateOfBirth('1/1/2000');  //Call public function
    employee.id = 9;                     //Set up member value
    //employee.setFName('Ram');  //can not call Private Privileged method
    alert(employee.toString());  //See the changed object

}

模块模式在大多数情况下是正确的。但是如果您有数千个实例,类可以节省内存。如果需要考虑节省内存,并且您的对象包含少量私有数据,但有大量公共函数,那么您将希望所有公共函数都驻留在.prototype中以节省内存。

这是我想到的:

var MyClass = (function () {
    var secret = {}; // You can only getPriv() if you know this
    function MyClass() {
        var that = this, priv = {
            foo: 0 // ... and other private values
        };
        that.getPriv = function (proof) {
            return (proof === secret) && priv;
        };
    }
    MyClass.prototype.inc = function () {
        var priv = this.getPriv(secret);
        priv.foo += 1;
        return priv.foo;
    };
    return MyClass;
}());
var x = new MyClass();
x.inc(); // 1
x.inc(); // 2

对象priv包含私有属性。它可以通过公共函数getPriv()访问,但该函数返回false,除非您将secret传递给它,并且只有在主闭包中才知道。

既然每个人都在这里张贴自己的代码,我也要这样做…

我喜欢Crockford,因为他在Javascript中引入了真正的面向对象模式。但他也产生了一个新的误解,那个“那个”。

那么他为什么要用"that = this"呢?这和私人活动完全没有关系。它与内部函数有关!

因为根据Crockford的说法,这是有bug的代码:

Function Foo( ) {
    this.bar = 0; 
    var foobar=function( ) {
        alert(this.bar);
    }
} 

所以他建议这样做:

Function Foo( ) {
    this.bar = 0;
    that = this; 
    var foobar=function( ) {
        alert(that.bar);
    }
}

就像我说的,我很确定Crockford对这个和这个的解释是错误的(但他的代码肯定是正确的)。或者他只是在愚弄Javascript世界,知道谁在复制他的代码?我不知道……我不是浏览器极客

EDIT

啊,这就是问题所在:'var that = this;'在JavaScript中是什么意思?

所以Crockie的解释是错误的....但他的代码是正确的,所以他还是个好人。:))

var TestClass = function( ) {

    var privateProperty = 42;

    function privateMethod( ) {
        alert( "privateMethod, " + privateProperty );
    }

    this.public = {
        constructor: TestClass,

        publicProperty: 88,
        publicMethod: function( ) {
            alert( "publicMethod" );
            privateMethod( );
        }
    };
};
TestClass.prototype = new TestClass( ).public;


var myTestClass = new TestClass( );

alert( myTestClass.publicProperty );
myTestClass.publicMethod( );

alert( myTestClass.privateMethod || "no privateMethod" );

类似于georgebrock,但不太啰嗦(恕我直言) 这样做有什么问题吗?(我哪儿都没见过)

编辑:我意识到这有点没用,因为每个独立的实例化都有自己的公共方法副本,从而破坏了原型的使用。

2021年这里!

这个polyfill有效地隐藏了你的私有属性和方法,当你试图读取你的私有属性时返回undefined,当你试图执行你的私有方法时返回TypeError,从而有效地使它们对外部都是private,但让你通过使用你的公共方法访问它们。

如果你检查它,你会发现它很容易实现。在大多数情况下,你不需要做任何奇怪的事情,如使用代理对象,下划线函数(_myprivate), getter或setter。都不是。唯一需要做的事情是在构造函数中放置一段类似的代码片段,目的是让您向外界公开您的公共接口。

((self) => ({
      pubProp: self.pubProp,
      // More public properties to export HERE
      // ...
      pubMethod: self.pubMethod.bind(self)
      // More public mehods to export HERE
      // Be sure bind each of them to self!!!
      // ... 
 }))(self);

上面的代码就是魔术发生的地方。它是一个IIFE,返回一个对象,其中只包含您想要公开并绑定到第一次实例化的对象的上下文的属性和方法。

你仍然可以访问你的隐藏属性和方法,但只能通过你的公共方法,就像OOP应该做的那样。 将这部分代码视为module.exports

顺便说一句,这是没有使用最新的ECMAScript 2022 #添加到语言中。

'use strict'; class MyClass { constructor(pubProp) { let self = this; self.pubProp = pubProp; self.privProp = "I'm a private property!"; return ((self) => ({ pubProp: self.pubProp, // More public properties to export HERE // ... pubMethod: self.pubMethod.bind(self) // More public mehods to export HERE // Be sure to bind each of them to self!!! // ... }))(self); } pubMethod() { console.log("I'm a public method!"); console.log(this.pubProp); return this.privMethod(); } privMethod() { console.log("I'm a private method!"); return this.privProp } } const myObj = new MyClass("I'm a public property!"); console.log("***DUMPING MY NEW INSTANCE***"); console.dir(myObj); console.log(""); console.log("***TESTING ACCESS TO PUBLIC PROPERTIES***"); console.log(myObj.pubProp); console.log(""); console.log("***TESTING ACCESS TO PRIVATE PROPERTIES***"); console.log(myObj.privProp); console.log(""); console.log("***TESTING ACCESS TO PUBLIC METHODS***"); console.log("1. pubMethod access pubProp "); console.log("2. pubMethod calls privMethod"); console.log("3. privMethod access privProp"); console.log("") console.log(myObj.pubMethod()); console.log(""); console.log("***TESTING ACCESS TO PRIVATE METHODS***"); console.log(myObj.privMethod());

看看我的主旨