Summary

  • private variables are declared with the 'var' keyword inside the object, and can only be accessed by private functions and privileged methods.
  • private functions are declared inline inside the object's constructor (or alternatively may be defined via var functionName=function(){...}) and may only be called by privileged methods (including the object's constructor).
  • privileged methods are declared with this.methodName=function(){...} and may invoked by code external to the object.
  • public properties are declared with this.variableName and may be read/written from outside the object.
  • public methods are defined by Classname.prototype.methodName = function(){...} and may be called from outside the object.
  • prototype properties are defined by Classname.prototype.propertyName = someValue
  • static properties are defined by Classname.propertyName = someValue

(different between static and prototype properties)

Example

In this example, a person's name and race are set at birth and may never be changed. When created, a person starts out at year 1 and a hidden maximum age is determined for that person. The person has a weight which is modified by eating (tripling their weight) or exercising (halfing it). Every time the person eats or exercises, they grow a year older. The person object has a publicly accessible 'clothing' property which anyone can modify, as well as a dirtFactor which can be modified manually (throwing dirt on or scrubbing it off), but which increases every time the person eats or exercises, and is reduced by the use of the shower() method.

The Example Code

 function Person(n,race){
this.constructor.population++; // this.constructor equal Person // ************************************************************************
// PRIVATE VARIABLES AND FUNCTIONS
// ONLY PRIVELEGED METHODS MAY VIEW/EDIT/INVOKE
// ***********************************************************************
var alive=true, age=1;
var maxAge=70+Math.round(Math.random()*15)+Math.round(Math.random()*15); // Math.random() return an random 0-1
function makeOlder(){ return alive = (++age <= maxAge) } // makeOlder cann't direct access outside Person var myName=n?n:"John Doe";
var weight=1; // ************************************************************************
// PRIVILEGED METHODS
// MAY BE INVOKED PUBLICLY AND MAY ACCESS PRIVATE ITEMS
// MAY NOT BE CHANGED; MAY BE REPLACED WITH PUBLIC FLAVORS
// ************************************************************************
this.toString=this.getName=function(){ return myName } this.eat=function(){
if (makeOlder()){
this.dirtFactor++;
return weight*=3;
} else alert(myName+" can't eat, he's dead!");
}
this.exercise=function(){
if (makeOlder()){
this.dirtFactor++;
return weight/=2;
} else alert(myName+" can't exercise, he's dead!");
}
this.weigh=function(){ return weight }
this.getRace=function(){ return race }
this.getAge=function(){ return age }
this.muchTimePasses=function(){ age+=50; this.dirtFactor=10; } // ************************************************************************
// PUBLIC PROPERTIES -- ANYONE MAY READ/WRITE
// ************************************************************************
this.clothing="nothing/naked";
this.dirtFactor=0;
} // ************************************************************************
// PUBLIC METHODS -- ANYONE MAY READ/WRITE
// ************************************************************************
Person.prototype.beCool = function(){ this.clothing="khakis and black shirt" }
Person.prototype.shower = function(){ this.dirtFactor=2 }
Person.prototype.showLegs = function(){ alert(this+" has "+this.legs+" legs") }
Person.prototype.amputate = function(){ this.legs-- } // ************************************************************************
// PROTOTYOPE PROERTIES -- ANYONE MAY READ/WRITE (but may be overridden)
// ************************************************************************
Person.prototype.legs=2; // ************************************************************************
// STATIC PROPERTIES -- ANYONE MAY READ/WRITE
// ************************************************************************
Person.population = 0;
 // Here is the code that uses the Person class
function RunGavinsLife(){
var gk=new Person("Gavin","caucasian"); //New instance of the Person object created.
var lk=new Person("Lisa","caucasian"); //New instance of the Person object created.
alert("There are now "+Person.population+" people"); gk.showLegs(); lk.showLegs(); //Both share the common 'Person.prototype.legs' variable when looking at 'this.legs' gk.race = "hispanic"; //Sets a public variable, but does not overwrite private 'race' variable.
alert(gk+"'s real race is "+gk.getRace()); //Returns 'caucasian' from private 'race' variable set at create time.
gk.eat(); gk.eat(); gk.eat(); //weight is 3...then 9...then 27
alert(gk+" weighs "+gk.weigh()+" pounds and has a dirt factor of "+gk.dirtFactor); gk.exercise(); //weight is now 13.5
gk.beCool(); //clothing has been update to current fashionable levels
gk.clothing="Pimp Outfit"; //clothing is a public variable that can be updated to any funky value
gk.shower();
alert("Existing shower technology has gotten "+gk+" to a dirt factor of "+gk.dirtFactor); gk.muchTimePasses(); //50 Years Pass
Person.prototype.shower=function(){ //Shower technology improves for everyone
this.dirtFactor=0;
}
gk.beCool=function(){ //Gavin alone gets new fashion ideas
this.clothing="tinfoil";
}; gk.beCool(); gk.shower();
alert("Fashionable "+gk+" at "
+gk.getAge()+" years old is now wearing "
+gk.clothing+" with dirt factor "
+gk.dirtFactor); gk.amputate(); //Uses the prototype property and makes a public property
gk.showLegs(); lk.showLegs(); //Lisa still has the prototype property gk.muchTimePasses(); //50 Years Pass...Gavin is now over 100 years old.
gk.eat(); //Complains about extreme age, death, and inability to eat.
}

Notes

  • maxAge is a private variable with no privileged accessor method; as such, there is no way to publicly get or set it.
  • race is a private variable defined only as an argument to the contructor. Variables passed into the constructor are available to the object as private variables.
  • The 'tinfoil' beCool() fashion method was applied only to the gk object, not the entire Personclass. Other people created and set to beCool() would still use the original 'khakis and black shirt' clothing that Gavin eschewed later in life.
  • Note the implicit call to the gk.toString() method when using string concatenation. It is this which allows the code alert(gk+' is so cool.') to put the word 'Gavin' in there, and is equivalent to alert(gk.toString()+' is so cool.'). Every object of every type in JS has a.toString() method, but you can override it with your own.
  • You cannot (to my knowledge) assign public methods of a class inside the main object constructor...you must use the prototype property externally, as above with the beCool() andshower() methods.
  • As I attempted to show with the Person.prototype.legs property and the amputate() function, prototype properties are shared by all object instances. Asking for lk.legs yields '2' by looking at the single prototype property. However, attempting to change this value using either gk.legs=1or (in the Person object) this.legs=1 ends up making a new public property of the object specific to that instance. (This is why calling gk.amputate() only removed a leg from Gavin, but not Lisa.) To modify a prototype property, you must use Person.prototype.legs=1 or something likethis.constructor.prototype.legs=1. (I say 'something like' because I discovered thatthis.constructor is not available inside private functions of the object, since this refers to the window object in that scope.)
  • Wherever an anonymous function is declared inline with
    foo = function(p1,p2){ some code }
    the new Function() constructor is NOT equivalent, e.g.
    foo = new Function('p1','p2','code');
    since the latter runs in the global scope--instead of inheriting the scope of the constructor function--thus preventing it from accessing the private variables.
  • As noted above in the code comments, the act of setting gk.race to some value did NOT overwrite the private race variable. Although it would be a dumb idea, you can have both private and public variables with the same name. For example, the yell() method in the following class will yield different values for foo and this.foo:
    function StupidClass(){ 
    var foo = "internal";
    this.foo = "external";
    this.yell=function(){ alert("Internal foo is "+foo+"\nExternal foo is "+this.foo) } 
    }
  • Private functions and privileged methods, like private variables and public properties, are instantiated with each new object created. So each time new Person() is called, new copies ofmakeOlder(), toString(), getName(), eat(), exercise(), weigh(), getRace(), getAge(), and muchTimePasses() are created. For every Person, each time. Contrast this with public methods (only one copy of beCool() and shower() exist no matter how many Person objects are created) and you can see that for memory/performance reasons it can be preferable to give up some degree of object protection and instead use only public methods.

Note that doing so requires making private variables public (since without privileged accessor methods there would be no way to use them) so the public methods can get at them...and which also allows external code to see/destroy these variables. The memory/performance optimization of using only public properties and methods has consequences which may make your code less robust.

For example, in the above age and maxAge are private variables; age can only be accessed externally through getAge() (it cannot be set) and maxAge cannot be read or set externally. Changing those to be public properties would allow any code to do something like gk.maxAge=1; gk.age=200; which not only does it not make sense (you shouldn't be able to manipulate someone's age or lifespan directly), but by setting those values directly the alive variable wouldn't properly be updated, leaving your Person object in a broken state.

Quote From:

OOP in JS, Part 1 : Public/Private Variables and Methods

See Also:

Object-Oriented JavaScript Tip: Creating Static Methods, Instance Methods

How To Get Private, Privileged, Public And Static Members (Properties And Methods)

OOP in JS Public/Private Variables and Methods的更多相关文章

  1. 深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

    访问修饰符(或者叫访问控制符)是面向对象语言的特性之一,用于对类.类成员函数.类成员变量进行访问控制.同时,访问控制符也是语法保留关键字,用于封装组件. Public, Private, Protec ...

  2. [Java] public, private, final and basic rules for naming.

    1. Access: public, private, protected public: Any other class can access a public field or method. ( ...

  3. JavaScript Patterns 5.3 Private Properties and Methods

    All object members are public in JavaScript. var myobj = { myprop : 1, getProp : function() { return ...

  4. php class中public,private,protected的区别,以及实例

    一,public,private,protected的区别 public:权限是最大的,可以内部调用,实例调用等. protected: 受保护类型,用于本类和继承类调用. private: 私有类型 ...

  5. OOP in JS - Inheritance

    Summary You cause a class to inherit using ChildClassName.prototype = new ParentClass();. You need t ...

  6. PHP中public,private,protected,abstract等关键字用法详解

    PHP中常用的关键字 在PHP中包含了很多对函数和类进行限制的关键字,常用的通常有abstract,final,interface,public,protected,private,static等等, ...

  7. python之private variables

    [python之private variables] “Private” instance variables that cannot be accessed except from inside a ...

  8. Public Private Protect Inheritance and access specifiers

    In the previous lessons on inheritance, we've been making all of our data members public in order to ...

  9. 訪问控制 protected, public, private 对照

    OOP 3大特性:数据抽象,继承,动态绑定 3中訪问标号 protected, public, private 对照 用类进行数据抽象:用继承类继承基类的成员,实现继承.通过将基类对应函数声明为vir ...

随机推荐

  1. SVN-钩子祥解与配置

    钩子脚本的具体写法就是操作系统中shell脚本程序的写法,请根据自己SVN所在的操作系统和shell程序进行相应的写作 所谓钩子就是与一些版本库事件触发的程序,例如新修订版本的创建,或是未版本化属性的 ...

  2. Django入门实践(二)

    Django入门实践(二) Django模板简单实例 上篇中将html写在了views中,这种混合方式(指Template和views混在一起)不适合大型开发,而且代码不易管理和维护,下面就用Djan ...

  3. sphinx2.8.8的配置文件

    # # Sphinx configuration file sample # # WARNING! While this sample file mentions all available opti ...

  4. wireshark查看sip协议流

    选择中你要查看的sip消息-----右键--follow udp stream,就可以查看出消息流的整个流程.

  5. Bitmap的一个简单实现

    一.Bitmap简介 Bitmap是一种常用的数据结构,其实就是一个连续的数组,主要是用于映射关系,如映射整数,一位代表一个数,即这里假设Bitmap有100Bytes * 8 这么多的位,那么这里可 ...

  6. ASP.NET Core + Angular 2 Template for Visual Studio

    多个月以来,我和多个Github上的社区贡献者一起建立支持库.包,我们最终的目的是希望完成这样一个作为起点的模板,也就是基于把Typescript代码和Angular2宿主在ASP.NET Core项 ...

  7. 开源中文分词工具探析(三):Ansj

    Ansj是由孙健(ansjsun)开源的一个中文分词器,为ICTLAS的Java版本,也采用了Bigram + HMM分词模型(可参考我之前写的文章):在Bigram分词的基础上,识别未登录词,以提高 ...

  8. EL表达式学习

    EL表达式取值 1.EL表达式的语法格式很简单: 以前编写jsp代码时,如果要获取表单中的用户名,一般使用 <%=request.getParameter("name")%& ...

  9. 通过Shell脚本读取properties文件中的参数时遇到\r换行符的问题

    今天在编写微服务程序启动脚本的时候,遇到一个比较奇葩的问题,下面给出具体描述: 目标:通过读取maven插件打包时生成的pom.properties文件,获取里面的应用名称和应用版本号,然后拼接得到s ...

  10. Python 3

    #对于任意可迭代对象可使用序列拆分操作符*进行拆分 #可用iterable对分片进行赋值等操作(相当于del分片并把iterable插入其中,所以二者长度可以不同) #del取消对象引用与数据项之间的 ...