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


当前回答

老问题,但这是一个相当简单的任务,可以用核心JS正确解决…没有ES6的Class抽象。事实上,据我所知,类抽象甚至不能解决这个问题。

我们既可以使用老的构造函数,也可以使用Object.create()更好地完成这项工作。让我们先从构造函数开始。这本质上是一个与georgebrock的答案相似的解决方案,georgebrock的答案受到了批评,因为所有由Restaurant构造函数创建的餐厅都将具有相同的私有方法。我会努力克服这个限制。

function restaurantFactory(name,menu){ function Restaurant(name){ this.name = name; } function prototypeFactory(menu){ // This is a private function function calculateBill(item){ return menu[item] || 0; } // This is the prototype to be return { constructor: Restaurant , askBill : function(...items){ var cost = items.reduce((total,item) => total + calculateBill(item) ,0) return "Thank you for dining at " + this.name + ". Total is: " + cost + "\n" } , callWaiter : function(){ return "I have just called the waiter at " + this.name + "\n"; } } } Restaurant.prototype = prototypeFactory(menu); return new Restaurant(name,menu); } var menu = { water: 1 , coke : 2 , beer : 3 , beef : 15 , rice : 2 }, name = "Silver Scooop", rest = restaurantFactory(name,menu); console.log(rest.callWaiter()); console.log(rest.askBill("beer", "beef"));

现在显然我们不能从外部访问菜单,但我们可以很容易地重命名餐厅的name属性。

这也可以用object .create()来完成,在这种情况下,我们跳过构造函数,简单地像var rest = object .create(prototypeFactory(menu))那样做,然后像rest.name = name那样将name属性添加到rest对象。

其他回答

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());

看看我的主旨

在这些情况下,当你有一个公共API,并且你想要私有和公共的方法/属性时,我总是使用模块模式。这个模式在YUI库中很流行,详细信息可以在这里找到:

http://yuiblog.com/blog/2007/06/12/module-pattern/

它非常简单明了,其他开发人员也很容易理解。举个简单的例子:

var MYLIB = function() {  
    var aPrivateProperty = true;
    var aPrivateMethod = function() {
        // some code here...
    };
    return {
        aPublicMethod : function() {
            aPrivateMethod(); // okay
            // some code here...
        },
        aPublicProperty : true
    };  
}();

MYLIB.aPrivateMethod() // not okay
MYLIB.aPublicMethod() // okay

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

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();
    }
}

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

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

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!'