要创建一个带有公共方法的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的文章几次,但它似乎不像“私有”方法可以被公共方法调用,而“特权”方法可以被外部调用。


当前回答

我想到了这个:编辑:实际上,有人已经链接到一个相同的解决方案。咄!

var Car = function() {
}

Car.prototype = (function() {
    var hotWire = function() {
        // Private code *with* access to public properties through 'this'
        alert( this.drive() ); // Alerts 'Vroom!'
    }

    return {
        steal: function() {
            hotWire.call( this ); // Call a private method
        },
        drive: function() {
            return 'Vroom!';
        }
    };
})();

var getAwayVechile = new Car();

hotWire(); // Not allowed
getAwayVechile.hotWire(); // Not allowed
getAwayVechile.steal(); // Alerts 'Vroom!'

其他回答

ES2021 / ES12 -私有方法

私有方法名以哈希前缀#开头,并且只能在定义它的类内部访问。

class Restaurant {

  // private method
  #private_stuff() {
    console.log("private stuff");
  }

  // public method
  buy_food() {
    this.#private_stuff();
  }

};

const restaurant = new Restaurant();
restaurant.buy_food(); // "private stuff";
restaurant.private_stuff(); // Uncaught TypeError: restaurant.private_stuff is not a function

你可以这样做,但缺点是它不能成为原型的一部分:

function Restaurant() {
    var myPrivateVar;

    var private_stuff = function() {  // Only visible inside Restaurant()
        myPrivateVar = "I can set this here!";
    }

    this.use_restroom = function() {  // use_restroom is visible to all
        private_stuff();
    }

    this.buy_food = function() {   // buy_food is visible to all
        private_stuff();
    }
}
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,但不太啰嗦(恕我直言) 这样做有什么问题吗?(我哪儿都没见过)

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

模块模式在大多数情况下是正确的。但是如果您有数千个实例,类可以节省内存。如果需要考虑节省内存,并且您的对象包含少量私有数据,但有大量公共函数,那么您将希望所有公共函数都驻留在.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传递给它,并且只有在主闭包中才知道。

你必须在你实际的构造函数周围放一个闭包,在那里你可以定义你的私有方法。 要通过这些私有方法改变实例的数据,你必须给它们一个"this",要么作为函数参数,要么用.apply(this)调用这个函数:

var Restaurant = (function(){
    var private_buy_food = function(that){
        that.data.soldFood = true;
    }
    var private_take_a_shit = function(){
        this.data.isdirty = true;   
    }
    // New Closure
    function restaurant()
    {
        this.data = {
            isdirty : false,
            soldFood: false,
        };
    }

    restaurant.prototype.buy_food = function()
    {
       private_buy_food(this);
    }
    restaurant.prototype.use_restroom = function()
    {
       private_take_a_shit.call(this);
    }
    return restaurant;
})()

// TEST:

var McDonalds = new Restaurant();
McDonalds.buy_food();
McDonalds.use_restroom();
console.log(McDonalds);
console.log(McDonalds.__proto__);