523

要使用公共方法创建 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_foodanduse_restroom方法调用但不能由类的用户在外部调用的私有方法?

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

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

但这不应该工作:

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

我如何定义private_stuff为私有方法,以便这两个都成立?

我已经阅读了Doug Crockford 的文章几次,但似乎“私有”方法不能被公共方法调用,而“特权”方法可以在外部调用。

4

34 回答 34

439

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

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();
    }
}
于 2008-09-11T01:26:52.583 回答
201

使用自调用函数并调用

JavaScript 使用原型并且没有像面向对象语言那样的类(或方法)。JavaScript 开发人员需要在 JavaScript 中思考。

维基百科引用:

与许多面向对象的语言不同,函数定义和方法定义之间没有区别。相反,区别发生在函数调用期间。当函数作为对象的方法被调用时,函数的本地 this 关键字将绑定到该对象以进行该调用。

使用自调用函数调用函数调用私有“方法”的解决方案:

var MyObject = (function () {
    
  // Constructor
  function MyObject(foo) {
    this._foo = foo;
  }

  function privateFun(prefix) {
    return prefix + this._foo;
  }
    
  MyObject.prototype.publicFun = function () {
    return privateFun.call(this, ">>");
  }
    
  return MyObject;

}());
var myObject = new MyObject("bar");
myObject.publicFun();      // Returns ">>bar"
myObject.privateFun(">>"); // ReferenceError: private is not defined

call 函数允许我们使用适当的上下文 ( ) 调用私有函数this

使用 Node.js 更简单

如果您使用的是Node.js,则不需要IIFE,因为您可以利用模块加载系统

function MyObject(foo) {
  this._foo = foo;
}
    
function privateFun(prefix) {
  return prefix + this._foo;
}

MyObject.prototype.publicFun = function () {
  return privateFun.call(this, ">>");
}
    
module.exports= MyObject;

加载文件:

var MyObject = require("./MyObject");
    
var myObject = new MyObject("bar");
myObject.publicFun();      // Returns ">>bar"
myObject.privateFun(">>"); // ReferenceError: private is not defined

(新!)未来 JavaScript 版本中的本地私有方法

TC39私有方法和 JavaScript 类的 getter/setter提案处于第 3 阶段。这意味着很快,JavaScript 将在本地实现私有方法!

请注意,现代 JavaScript 版本中已经存在JavaScript 私有类字段。

这是如何使用它的示例:

class MyObject {

  // Private field
  #foo;
    
  constructor(foo) {
    this.#foo = foo;
  }

  #privateFun(prefix) {
   return prefix + this.#foo;
  }
    
  publicFun() {
    return this.#privateFun(">>");
  }

}

您可能需要一个JavaScript 转译器/编译器才能在旧的 JavaScript 引擎上运行此代码。

PS:如果您想知道为什么要使用#前缀,请阅读此.

(已弃用)带有 Bind 运算符的 ES7

警告:绑定运算符 TC39 命题即将失效https://github.com/tc39/proposal-bind-operator/issues/53#issuecomment-374271822

bind 操作符::是一个 ECMAScript提议在 Babel阶段 0)中实现。

export default class MyObject {
  constructor (foo) {
    this._foo = foo;
  }

  publicFun () {
    return this::privateFun(">>");
  }
}

function privateFun (prefix) {
  return prefix + this._foo;
}
于 2014-08-07T01:34:39.930 回答
164

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

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

于 2008-09-11T01:27:38.573 回答
37

在这些情况下,当您拥有公共 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
于 2008-09-11T02:30:32.540 回答
21

这是我创建的课程,以了解 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

}
于 2012-02-15T05:43:12.013 回答
13

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

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!'
于 2009-09-01T10:13:29.010 回答
12

您现在可以使用es10 私有方法来执行此操作。您只需要#在方法名称之前添加一个。

class ClassWithPrivateMethod {
  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
    return #privateMethod();
  }
}
于 2019-12-25T01:17:27.630 回答
11

我认为由于对闭包缺乏了解,此类问题一次又一次地出现。Сlosures 是 JS 中最重要的东西。每个 JS 程序员都必须去感受它的精髓。

1.首先我们需要做单独的范围(闭包)。

function () {

}

2.在这方面,我们可以为所欲为。没有人会知道。

function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
}

3.为了让全世界知道我们的餐厅班,我们必须从关闭中归还它。

var Restaurant = (function () {
    // Restaurant definition
    return Restaurant
})()

4.最后,我们有:

var Restaurant = (function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
    return Restaurant
})()

5.此外,这种方法具有继承和模板的潜力

// Abstract class
function AbstractRestaurant(skills) {
    var name
    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return skills && name in skills ? skills[name]() : null
    }
    return Restaurant
}

// Concrete classes
SushiRestaurant = AbstractRestaurant({ 
    sushi: function() { return new Sushi() } 
})

PizzaRestaurant = AbstractRestaurant({ 
    pizza: function() { return new Pizza() } 
})

var r1 = new SushiRestaurant('Yo! Sushi'),
    r2 = new PizzaRestaurant('Dominos Pizza')

r1.getFood('sushi')
r2.getFood('pizza')

我希望这可以帮助某人更好地理解这个主题

于 2013-08-14T03:06:00.707 回答
10

就个人而言,我更喜欢以下在 JavaScript 中创建类的模式:

var myClass = (function() {
    // Private class properties go here

    var blueprint = function() {
        // Private instance properties go here
        ...
    };

    blueprint.prototype = { 
        // Public class properties go here
        ...
    };

    return  {
         // Public class properties go here
        create : function() { return new blueprint(); }
        ...
    };
})();

如您所见,它允许您定义类属性和实例属性,每个属性都可以是公共的和私有的。


演示

var Restaurant = function() {
    var totalfoodcount = 0;        // Private class property
    var totalrestroomcount  = 0;   // Private class property
    
    var Restaurant = function(name){
        var foodcount = 0;         // Private instance property
        var restroomcount  = 0;    // Private instance property
        
        this.name = name
        
        this.incrementFoodCount = function() {
            foodcount++;
            totalfoodcount++;
            this.printStatus();
        };
        this.incrementRestroomCount = function() {
            restroomcount++;
            totalrestroomcount++;
            this.printStatus();
        };
        this.getRestroomCount = function() {
            return restroomcount;
        },
        this.getFoodCount = function() {
            return foodcount;
        }
    };
   
    Restaurant.prototype = {
        name : '',
        buy_food : function(){
           this.incrementFoodCount();
        },
        use_restroom : function(){
           this.incrementRestroomCount();
        },
        getTotalRestroomCount : function() {
            return totalrestroomcount;
        },
        getTotalFoodCount : function() {
            return totalfoodcount;
        },
        printStatus : function() {
           document.body.innerHTML
               += '<h3>Buying food at '+this.name+'</h3>'
               + '<ul>' 
               + '<li>Restroom count at ' + this.name + ' : '+ this.getRestroomCount() + '</li>'
               + '<li>Food count at ' + this.name + ' : ' + this.getFoodCount() + '</li>'
               + '<li>Total restroom count : '+ this.getTotalRestroomCount() + '</li>'
               + '<li>Total food count : '+ this.getTotalFoodCount() + '</li>'
               + '</ul>';
        }
    };

    return  { // Singleton public properties
        create : function(name) {
            return new Restaurant(name);
        },
        printStatus : function() {
          document.body.innerHTML
              += '<hr />'
              + '<h3>Overview</h3>'
              + '<ul>' 
              + '<li>Total restroom count : '+ Restaurant.prototype.getTotalRestroomCount() + '</li>'
              + '<li>Total food count : '+ Restaurant.prototype.getTotalFoodCount() + '</li>'
              + '</ul>'
              + '<hr />';
        }
    };
}();

var Wendys = Restaurant.create("Wendy's");
var McDonalds = Restaurant.create("McDonald's");
var KFC = Restaurant.create("KFC");
var BurgerKing = Restaurant.create("Burger King");

Restaurant.printStatus();

Wendys.buy_food();
Wendys.use_restroom();
KFC.use_restroom();
KFC.use_restroom();
Wendys.use_restroom();
McDonalds.buy_food();
BurgerKing.buy_food();

Restaurant.printStatus();

BurgerKing.buy_food();
Wendys.use_restroom();
McDonalds.buy_food();
KFC.buy_food();
Wendys.buy_food();
BurgerKing.buy_food();
McDonalds.buy_food();

Restaurant.printStatus();

另请参阅此 Fiddle

于 2017-06-07T22:02:10.560 回答
9

所有这些关闭都会让你付出代价。确保您测试速度影响,尤其是在 IE 中。您会发现使用命名约定会更好。仍然有很多企业网络用户被迫使用 IE6...

于 2008-09-15T13:47:18.217 回答
9

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
于 2020-10-23T17:18:05.377 回答
5

不要那么冗长。它是 Javascript。使用命名约定

在 es6 类工作多年后,我最近开始了一个 es5 项目的工作(使用已经非常冗长的 requireJS)。我已经一遍又一遍地讨论了这里提到的所有策略,基本上归结为使用命名约定

  1. Javascript 没有范围关键字,例如private. 其他进入 Javascript 的开发人员会预先知道这一点。因此,一个简单的命名约定就足够了。带有下划线前缀的简单命名约定解决了私有属性和私有方法的问题。
  2. 出于速度原因,让我们利用 Prototype,但不要再冗长了。让我们尽量让 es5“类”看起来与我们在其他后端语言中可能期望的一样接近(并将每个文件视为一个类,即使我们不需要返回实例)。
  3. 让我们用一个更现实的模块情况来演示(我们将使用旧的 es5 和旧的 requireJs)。

我的工具提示.js

    define([
        'tooltip'
    ],
    function(
        tooltip
    ){

        function MyTooltip() {
            // Later, if needed, we can remove the underscore on some
            // of these (make public) and allow clients of our class
            // to set them.
            this._selector = "#my-tooltip"
            this._template = 'Hello from inside my tooltip!';
            this._initTooltip();
        }

        MyTooltip.prototype = {
            constructor: MyTooltip,

            _initTooltip: function () {
                new tooltip.tooltip(this._selector, {
                    content: this._template,
                    closeOnClick: true,
                    closeButton: true
                });
            }
        }

        return {
            init: function init() {
               new MyTooltip();  // <-- Our constructor adds our tooltip to the DOM so not much we need to do after instantiation.
            }

            // You could instead return a new instantiation, 
            // if later you do more with this class.
            /* 
            create: function create() {
               return new MyTooltip();
            }
            */
        }
    });
于 2018-07-22T23:32:41.463 回答
4

采用任何遵循 Crockford 的私有特权模式的解决方案。例如:

function Foo(x) {
    var y = 5;
    var bar = function() {
        return y * x;
    };

    this.public = function(z) {
        return bar() + x * z;
    };
}

在任何情况下,如果攻击者对 JS 上下文没有“执行”权限,他就无法访问任何“公共”或“私有”字段或方法。如果攻击者确实拥有该访问权限,他可以执行以下单行:

eval("Foo = " + Foo.toString().replace(
    /{/, "{ this.eval = function(code) { return eval(code); }; "
));

请注意,上面的代码对所有构造函数类型隐私都是通用的。这里的一些解决方案会失败,但应该清楚的是,几乎所有基于闭包的解决方案都可以像这样使用不同的replace()参数来破坏。

执行此操作后,任何创建的对象new Foo()都将具有一个eval方法,可以调用该方法来返回或更改构造函数闭包中定义的值或方法,例如:

f = new Foo(99);
f.eval("x");
f.eval("y");
f.eval("x = 8");

我可以看到的唯一问题是它不适用于只有一个实例并且它是在加载时创建的情况。但是没有理由实际定义原型,在这种情况下,攻击者可以简单地重新创建对象而不是构造函数,只要他有方法传递相同的参数(例如,它们是常量或从可用值计算)。

在我看来,这几乎使 Crockford 的解决方案毫无用处。由于“隐私”很容易打破他的解决方案的缺点(降低可读性和可维护性、降低性能、增加内存),因此基于“无隐私”原型的方法是更好的选择。

我通常使用前导下划线来标​​记方法__private_protected字段(Perl 风格),但在 JavaScript 中拥有隐私的想法只是表明它是一种被误解的语言。

因此,除了他的第一句话外,我不同意Crockford 。

那么如何在 JS 中获得真正的隐私呢?将所有需要私有的东西放在服务器端,并使用 JS 进行 AJAX 调用。

于 2014-08-18T15:01:18.713 回答
2

模块模式的巅峰之作:揭示模块模式

一个非常健壮的模式的一个巧妙的小扩展。

于 2008-09-11T03:10:32.367 回答
2

如果您想要具有公共函数访问私有函数的能力的全部公共和私有函数,请为这样的对象布局代码:

function MyObject(arg1, arg2, ...) {
  //constructor code using constructor arguments...
  //create/access public variables as 
  // this.var1 = foo;

  //private variables

  var v1;
  var v2;

  //private functions
  function privateOne() {
  }

  function privateTwon() {
  }

  //public functions

  MyObject.prototype.publicOne = function () {
  };

  MyObject.prototype.publicTwo = function () {
  };
}
于 2008-09-29T10:39:21.760 回答
2
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 类似,但不那么冗长(恕我直言)这样做有什么问题吗?(我在任何地方都没有看到)

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

于 2011-04-18T14:00:24.533 回答
2

那这个呢?

var Restaurant = (function() {

 var _id = 0;
 var privateVars = [];

 function Restaurant(name) {
     this.id = ++_id;
     this.name = name;
     privateVars[this.id] = {
         cooked: []
     };
 }

 Restaurant.prototype.cook = function (food) {
     privateVars[this.id].cooked.push(food);
 }

 return Restaurant;

})();

私有变量查找在立即函数的范围之外是不可能的。没有重复功能,节省内存。

缺点是查找私有变量很笨拙privateVars[this.id].cooked,打字很荒谬。还有一个额外的“id”变量。

于 2013-10-30T23:09:33.953 回答
2

这是迄今为止我最喜欢的关于私有/公共方法/成员和 javascript 中的实例化的内容:

这是文章:http ://www.sefol.com/?p=1090

这是一个例子:

var Person = (function () {

    //Immediately returns an anonymous function which builds our modules 
    return function (name, location) {

        alert("createPerson called with " + name);

        var localPrivateVar = name;

        var localPublicVar = "A public variable";

        var localPublicFunction = function () {
            alert("PUBLIC Func called, private var is :" + localPrivateVar)
        };

        var localPrivateFunction = function () {
            alert("PRIVATE Func called ")
        };

        var setName = function (name) {

            localPrivateVar = name;

        }

        return {

            publicVar: localPublicVar,

            location: location,

            publicFunction: localPublicFunction,

            setName: setName

        }

    }
})();


//Request a Person instance - should print "createPerson called with ben"
var x = Person("ben", "germany");

//Request a Person instance - should print "createPerson called with candide"
var y = Person("candide", "belgium");

//Prints "ben"
x.publicFunction();

//Prints "candide"
y.publicFunction();

//Now call a public function which sets the value of a private variable in the x instance
x.setName("Ben 2");

//Shouldn't have changed this : prints "candide"
y.publicFunction();

//Should have changed this : prints "Ben 2"
x.publicFunction();

JSFiddle:http: //jsfiddle.net/northkildonan/kopj3dt3/1/

于 2014-12-10T09:01:44.010 回答
2

在大多数情况下,模块模式是正确的。但是如果你有数千个实例,类可以节省内存。如果节省内存是一个问题,并且您的对象包含少量私有数据,但有很多公共函数,那么您将希望所有公共函数都存在于 .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包含私有属性。它可以通过 public function 访问,但是除非你将 传递给它,否则getPriv()这个函数会返回,而这只有在 main 闭包中才知道。falsesecret

于 2015-02-02T14:28:19.913 回答
2

将所有代码包装在匿名函数中:然后,所有函数将是私有的,只有附加到window对象的函数:

(function(w,nameSpacePrivate){
     w.Person=function(name){
         this.name=name;   
         return this;
     };

     w.Person.prototype.profilePublic=function(){
          return nameSpacePrivate.profile.call(this);
     };  

     nameSpacePrivate.profile=function(){
       return 'My name is '+this.name;
     };

})(window,{});

用这个 :

  var abdennour=new Person('Abdennour');
  abdennour.profilePublic();

小提琴

于 2015-06-25T05:48:30.753 回答
1

我更喜欢将私有数据存储在关联的WeakMap. 这允许您将公共方法保留在它们所属的原型上。对于大量对象,这似乎是处理此问题的最有效方法。

const data = new WeakMap();

function Foo(value) {
    data.set(this, {value});
}

// public method accessing private value
Foo.prototype.accessValue = function() {
    return data.get(this).value;
}

// private 'method' accessing private value
function accessValue(foo) {
    return data.get(foo).value;
}

export {Foo};
于 2018-02-16T19:55:30.813 回答
0

私有函数不能使用模块模式访问公共变量

于 2011-05-29T19:37:04.127 回答
0

由于每个人都在这里发布他自己的代码,我也会这样做......

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

那么他为什么要使用“that = this”呢?它与私有函数完全无关。它与内部功能有关!

因为根据 Crockford 的说法,这是错误的代码:

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 世界,想知道谁在复制他的代码?我不知道...我不是浏览器极客;D

编辑

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

所以克罗基的解释真的错了......但他的代码是正确的,所以他仍然是一个很棒的人。:))

于 2012-11-11T02:10:44.297 回答
0

一般来说,我将私有对象 _ 临时添加到对象中。您必须在该方法的“Power-constructor”中明确打开隐私。如果您从原型调用该方法,您将能够覆盖原型方法

  • 使公共方法在“Power-constructor”中可访问:(ctx 是对象上下文)

    ctx.test = GD.Fabric.open('test', GD.Test.prototype, ctx, _); // is a private object
    
  • 现在我有了这个 openPrivacy:

    GD.Fabric.openPrivacy = function(func, clss, ctx, _) {
        return function() {
            ctx._ = _;
            var res = clss[func].apply(ctx, arguments);
            ctx._ = null;
            return res;
        };
    };
    
于 2013-03-30T17:23:30.997 回答
0

您必须在您的实际构造函数周围放置一个闭包,您可以在其中定义您的私有方法。要通过这些私有方法更改实例的数据,您必须将“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__);
于 2013-05-17T09:25:15.367 回答
0

这就是我的工作:

需要您可以在此处找到的一类糖代码。还支持受保护的、继承的、虚拟的、静态的东西……

;( function class_Restaurant( namespace )
{
    'use strict';

    if( namespace[ "Restaurant" ] ) return    // protect against double inclusions

        namespace.Restaurant = Restaurant
    var Static               = TidBits.OoJs.setupClass( namespace, "Restaurant" )


    // constructor
    //
    function Restaurant()
    {
        this.toilets = 3

        this.Private( private_stuff )

        return this.Public( buy_food, use_restroom )
    }

    function private_stuff(){ console.log( "There are", this.toilets, "toilets available") }

    function buy_food     (){ return "food"        }
    function use_restroom (){ this.private_stuff() }

})( window )


var chinese = new Restaurant

console.log( chinese.buy_food()      );  // output: food
console.log( chinese.use_restroom()  );  // output: There are 3 toilets available
console.log( chinese.toilets         );  // output: undefined
console.log( chinese.private_stuff() );  // output: undefined

// and throws: TypeError: Object #<Restaurant> has no method 'private_stuff'
于 2013-08-14T18:49:07.407 回答
0
Class({  
    Namespace:ABC,  
    Name:"ClassL2",  
    Bases:[ABC.ClassTop],  
    Private:{  
        m_var:2  
    },  
    Protected:{  
        proval:2,  
        fight:Property(function(){  
            this.m_var--;  
            console.log("ClassL2::fight (m_var)" +this.m_var);  
        },[Property.Type.Virtual])  
    },  
    Public:{  
        Fight:function(){  
            console.log("ClassL2::Fight (m_var)"+this.m_var);  
            this.fight();  
        }  
    }  
});  

https://github.com/nooning/JSClass

于 2013-12-10T17:02:29.120 回答
0

我创建了一个新工具,允许您在原型 https://github.com/TremayneChrist/ProtectJS上拥有真正的私有方法

例子:

var MyObject = (function () {

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method, using (_)
    _private: function () {
      console.log('PRIVATE method has been called');
    }
  }

  return protect(MyObject);

})();

// Create an instance of the object
var mo = new MyObject();

// Call its methods
mo.public(); // Pass
mo._private(); // Fail
于 2014-01-16T16:18:11.673 回答
0

我知道这有点太晚了,但是这个怎么样?

var obj = function(){
    var pr = "private";
    var prt = Object.getPrototypeOf(this);
    if(!prt.hasOwnProperty("showPrivate")){
        prt.showPrivate = function(){
            console.log(pr);
        }
    }    
}

var i = new obj();
i.showPrivate();
console.log(i.hasOwnProperty("pr"));
于 2015-01-28T11:14:18.203 回答
0

这个问题已经有很多答案了,但没有一个能满足我的需要。所以我想出了自己的解决方案,我希望它对某人有用:

function calledPrivate(){
    var stack = new Error().stack.toString().split("\n");
    function getClass(line){
        var i = line.indexOf(" ");
        var i2 = line.indexOf(".");
        return line.substring(i,i2);
    }
    return getClass(stack[2])==getClass(stack[3]);
}

class Obj{
    privateMethode(){
        if(calledPrivate()){
            console.log("your code goes here");
        }
    }
    publicMethode(){
        this.privateMethode();
    }
}

var obj = new Obj();
obj.publicMethode(); //logs "your code goes here"
obj.privateMethode(); //does nothing

正如你所看到的,当在 javascript 中使用这种类型的类时,这个系统可以工作。据我所知,上面评论的方法都没有。

于 2016-05-10T14:37:52.670 回答
0

一个丑陋的解决方案,但它有效:

function Class(cb) {
    const self = {};

    const constructor = (fn) => {
        func = fn;    
    };

    const addPrivate = (fnName, obj) => {
        self[fnName] = obj;
    }

    const addPublic = (fnName, obj) => {
        this[fnName] = obj;
        self[fnName] = obj;
        func.prototype[fnName] = obj;
    }
    
    cb(constructor, addPrivate, addPublic, self);
    return func;
}

const test = new Class((constructor, private, public, self) => {
    constructor(function (test) {
        console.log(test)
    });
    public('test', 'yay');
    private('qwe', 'nay');
    private('no', () => {
        return 'hello'
    })
    public('asd', () => {
        return 'this is public'
    })
    public('hello', () => {
        return self.qwe + self.no() + self.asd()
    })
})
const asd = new test('qweqwe');
console.log(asd.hello());

于 2020-09-03T10:56:00.920 回答
0

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

我们可以使用良好的旧构造函数甚至更好地使用Object.create(). 让我们先使用构造函数。这本质上是与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"));

现在显然我们无法menu从外部访问,但我们可以轻松地重命名name餐厅的属性。

这也可以完成,Object.create()在这种情况下,我们跳过构造函数并简单地做 like var rest = Object.create(prototypeFactory(menu))并将 name 属性添加到rest对象之后 like rest.name = name

于 2021-01-03T16:49:09.693 回答
0

我知道这是一个老话题,但我试图找到一种方法来保持代码的“简单性”以实现可维护性并保持轻量级的内存负载。它带有这种模式。希望能帮助到你。

const PublicClass=function(priv,pub,ro){
    let _priv=new PrivateClass(priv,pub,ro);
    ['publicMethod'].forEach(k=>this[k]=(...args)=>_priv[k](...args));
    ['publicVar'].forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    ['readOnlyVar'].forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k]}));
};

class PrivateClass{
    constructor(priv,pub,ro){
        this.privateVar=priv;
        this.publicVar=pub;
        this.readOnlyVar=ro;
    }
    publicMethod(arg1,arg2){
        return this.privateMethod(arg1,arg2);
    }
    privateMethod(arg1,arg2){
        return arg1+''+arg2;
    }
}
// in node;
module.exports=PublicClass;
// in browser;
const PublicClass=(function(){
    // code here
    return PublicClass;
})();

旧浏览器的原理相同:

var PublicClass=function(priv,pub,ro){
    var scope=this;
    var _priv=new PrivateClass(priv,pub,ro);
    ['publicMethod'].forEach(function(k){
        scope[k]=function(){return _priv[k].apply(_priv,arguments)};
    });
    ['publicVar'].forEach(function(k){
        Object.defineProperty(scope,k,{get:function(){return _priv[k]},set:function(v){_priv[k]=v}});
    });
    ['readOnlyVar'].forEach(function(k){
        Object.defineProperty(scope,k,{get:function(){return _priv[k]}});
    });
};

var PrivateClass=function(priv,pub,ro){
    this.privateVar=priv;
    this.publicVar=pub;
    this.readOnlyVar=ro;
};
PrivateClass.prototype.publicMethod=function(arg1,arg2){
    return this.privateMethod(arg1,arg2);
};
PrivateClass.prototype.privateMethod=function(arg1,arg2){
    return arg1+''+arg2;
};

为了减轻公共类的冗长和负载,将此模式应用于构造函数:

const AbstractPublicClass=function(instanciate,inherit){
    let _priv=instanciate();
    inherit.methods?.forEach(k=>this[k]=(...args)=>_priv[k](...args));
    inherit.vars?.forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    inherit.readonly?.forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k]}));
};

AbstractPublicClass.static=function(_pub,_priv,inherit){
    inherit.methods?.forEach(k=>_pub[k]=(...args)=>_priv[k](...args));
    inherit.vars?.forEach(k=>Object.defineProperty(_pub,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    inherit.readonly?.forEach(k=>Object.defineProperty(_pub,k,{get:()=>_priv[k]}));
};

采用 :

// PrivateClass ...
PrivateClass.staticVar='zog';
PrivateClass.staticMethod=function(){return 'hello '+this.staticVar;};


const PublicClass=function(priv,pub,ro){
    AbstractPublicClass.apply(this,[()=>new PrivateClass(priv,pub,ro),{
        methods:['publicMethod'],
        vars:['publicVar'],
        readonly:['readOnlyVar']
    }]);
};
AbstractPublicClass.static(PublicClass,PrivateClass,{
    methods:['staticMethod'],
    vars:['staticVar']
});

PS:这种方法的默认值(大多数情况下可以忽略不计)与完整的公众相比,它可以占用很小的计算负载。但是,只要您不将它与高度请求的课程一起使用就可以了。

于 2021-04-23T18:45:46.513 回答
0

2021在这里!

当您尝试读取私有属性时,此 polyfill 有效地隐藏了您的私有属性和方法返回undefined ,当您尝试执行私有方法时返回TypeError,从而有效地使它们对外部都是私有的,但让您可以使用公共方法访问它们.

如果你检查它,你会发现它很容易实现。在大多数情况下,您不需要做任何古怪的事情,例如使用 Proxy 对象、下划线函数 (_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

顺便说一句,这是没有使用最新的 ES6“ # ”添加到语言。

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

检查我的要点

于 2021-08-30T00:59:47.590 回答