JavaScript私有方法

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

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

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

但是这不应该工作:

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

我如何将private_stuff定义为私有方法,这两种方法都适用?

我已经读了Doug Crockford的几次写作 ,但是看起来好像“私有”方法可以通过公共方法调用,“特权”方法可以从外部调用。

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

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

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

 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

使用自我调用功能和调用

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 

调用函数允许我们用适当的上下文( 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, '>>'); } exports.MyObject = MyObject; 

加载文件:

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

(实验)ES7与绑定操作符

bind operator ::是一个ECMAScript 提议,并在Babel ( 阶段0 )中实现。

 export default class MyObject { constructor (foo) { this._foo = foo; } publicFun () { return this::privateFun('>>'); } } function privateFun (prefix) { return prefix + this._foo; } 

加载文件:

 import MyObject from './MyObject'; let myObject = new MyObject('bar'); myObject.publicFun(); // Returns '>>bar' myObject.privateFun('>>'); // TypeError: myObject.privateFun is not a function 

在这些情况下,当你有一个公共的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 

这里是我为了解道格拉斯·克罗克福德(Douglas Crockford)在他的网站Private Members中建议的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 } 

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

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

我觉得这样的问题一次又一次地出现,是因为对封闭的理解不够。 JS是最重要的东西。 每个JS程序员都必须感受它的本质。

首先,我们需要制定单独的范围(封闭)。

 function () { } 

在这方面,我们可以做任何我们想做的事。 没有人会知道。

 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 } } 

来自“简明英汉词典”为了让全世界了解我们的餐厅,我们必须从封闭中退货。

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

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

 // 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') 

我希望这能帮助别人更好地理解这个话题

所有这些关闭将花费你。 确保你测试速度的影响,特别是在IE浏览器。 你会发现你的命名约定更好。 还有很多企业网站用户被迫使用IE6 …

采取任何克罗克福德的私人特权模式的解决方案。 例如:

 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中拥有隐私的想法只是表明它是如何被误解的语言。

所以我不同意克罗克福德,除了他的第一句话。

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

模块模式的神化: 揭示模块模式

一个整洁的小扩展到一个非常强大的模式。

如果您想要公有和私有函数的全部范围,并且具有公共函数访问私有函数的能力,则可以使用以下对象的布局代码:

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

我认为@domgblackwell和@James的方法存在的问题是,原型方法将会被创建的每个实例反复地定义。 但是,由于这是一个覆盖,它可能是从内存方面的问题。 它虽然在优雅上失去了点,因此每次定义这些方法都是相当丑陋的。

那这个呢?

 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”变量。

 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类似,但少一点冗长(恕我直言)这样做的任何问题? (我没有看到它在任何地方)

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

模块模式在大多数情况下是正确的。 但是,如果您有数千个实例,则类会节省内存。 如果保存内存是一个问题,你的对象包含少量的私人数据,但有很多的公共职能,那么你会希望所有的公共职能生活在。原型,以节省内存。

这就是我想到的:

 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 ,并且这只在主闭包内部是已知的。

将所有代码包装在匿名函数中:然后,所有的函数都是私有的,只有附加到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(); 

小提琴

就个人而言,我更喜欢以下模式在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(); 

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

由于每个人都在这里张贴自己的代码,我也会这样做…

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

那为什么他用“那=这个”呢? 这与私人功能完全无关。 它与内部功能有关!

因为根据克罗克福德这是错误的代码:

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

所以他建议这样做:

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

所以,正如我所说,我相当肯定,克罗克福德是错误的关于这个和这个(但他的代码是肯定的)的解释。 或者他只是在愚弄Javascript世界,知道谁在抄袭他的代码? 我不知道…我不是浏览器怪胎; D

编辑

啊,那就是关于什么 : “var that = this”是什么意思? 在JavaScript中的意思是?

所以克罗基对他的解释是错误的……但是他的代码是正确的,所以他仍然是一个伟大的人。 :))

一般来说,我将私人对象_临时添加到对象。 您必须在方法的“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; }; }; 

这就是我所做的:

需要一类糖代码, 你可以在这里找到 。 还支持保护,继承,虚拟,静态的东西…

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

I have created a new tool to allow you to have true private methods on the prototype 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 

You have to put a closure around your actual constructor-function, where you can define your private methods. To change data of the instances through these private methods, you have to give them "this" with them, either as an function argument or by calling this function with .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__); 

Here's what i enjoyed the most so far regarding private/public methods/members and instantiation in javascript:

here is the article: http://www.sefol.com/?p=1090

and here is the example:

 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/

I know it's a bit too late but how about this?

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

There are many answers on this question already, but nothing fitted my needs. So i came up with my own solution, I hope it is usefull for someone:

 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 

As you can see this system works when using this type of classes in javascript. As far as I figured out none of the methods commented above did.

See this answer for aa clean & simple 'class' solution with a private and public interface and support for composition

Interesting Posts