探讨在javascript实现类的方式在 javascript 中有很多方式来创建对象,所以创建对象的方式使用起来非常灵活。那么,到底哪一种方式是最恰当的对象创建方式呢?构造立即学习“Java免费学习笔记(深入)
”;
模式,原型模式还是对象原意模式(Object literal)呢?
立即学习“Java免费学习笔记(深入)
”;
但这些模式具体是怎么回事呢?
立即学习“Java免费学习笔记(深入)
”;
在开始讲解之前,让我们先清楚地介绍一下关于 javascript 基本知识。
立即学习“Java免费学习笔记(深入)
”;
有没有可能在 javascript 中实现面向对象编程的方式呢?
立即学习“Java免费学习笔记(深入)
”;
答案是可能的,javascript 是可以创建对象的!这种对象可以包含数据及能够操作数据的方法,甚至可以包含其他对象。它没有类但拥有构立即学习“Java免费学习笔记(深入)
”;
造函数;它没有类继承机制,但是可以通过原型(prototype)实现继承。
立即学习“Java免费学习笔记(深入)
”;
现在看起来,我们已经了解了在 javascript 中创建对象及实现基于对象编程时所必须的组成部分。
立即学习“Java免费学习笔记(深入)
”;
我们都知道 javascript 拥有私有变量。一个通过“var”关键字定义的变量,只能在函数体中被访问,而不能在函数外被访问。那么,如果立即学习“Java免费学习笔记(深入)
”;
我们不通过使用“var”关键字来定义变量会怎样呢?我们现在不对这个问题进行深入探讨,可能是通过“this”进行访问的,我会在另外的立即学习“Java免费学习笔记(深入)
”;
时间来详细讲述这个问题。
立即学习“Java免费学习笔记(深入)
”;
现在回到之前的问题。到底哪一种方式是最恰当的对象创建方式呢?
让我们用已经知晓的知识,通过创建Person的对象是来试验一下。
立即学习“Java免费学习笔记(深入)
”;
[javascript]var Person = {firstName : 'John',lastName : 'Cody',fullName : '',message : '',createFullName : function () {fullName = this.firstName + ' ' + this.lastName;},changeMessage : function (msg) {this.message = msg;},getMessage : function () {this.createFullName();return this.message + ' ' + fullName;}}Person.firstName = 'Eli';Person.lastName = 'Flowers'Person.changeMessage('welcome');var message = Person.getMessage(); // welcome Eli Flowers alert(message);立即学习“Java免费学习笔记(深入)
”;
这是对象原意模式(literal pattern)。这非常接近我们常创建对象的方式。如果你不需要关心私有/包装的成员,并且你知道不将创建这个对立即学习“Java免费学习笔记(深入)
”;
象的实例。那么,这种方式将会很适合你。公有的成员可以做所有私有成员的事情,不是吗?但是,这不是一个类,而是一个对象而已,不能立即学习“Java免费学习笔记(深入)
”;
被创建实例并且不能被继承。
立即学习“Java免费学习笔记(深入)
”;
让我们尝试下其他的方面:
立即学习“Java免费学习笔记(深入)
”;
[javascript]var Person = function() {this.firstName = 'John';this.lastName = 'Cody';var fullName = '';this.message = '';var _that = this;var createFullName = function () {fullName = _that.firstName + ' ' + _that.lastName;}this.changeMessage = function (msg) {this.message = msg;}this.getMessage = function () {createFullName();return this.message + ' ' + fullName;}}var person1 = new Person();person1.firstName = 'Eli';person1.lastName = 'Flowers'person1.changeMessage('welcome');var message = person1.getMessage(); // welcome Eli Flowers alert(message);立即学习“Java免费学习笔记(深入)
”;
立即学习“Java免费学习笔记(深入)
”;
这是一种构造模式的实例(Constructor Pattern)。那么,这是类还是对象呢?应该 两种都算是吧。我们能够在当请求时把它当做对象Person立即学习“Java免费学习笔记(深入)
”;
来使用。它毕竟也只是一个函数而已。然而,它可以通过使用“new”关键字来实现创建新的实例功能。
立即学习“Java免费学习笔记(深入)
”;
在使用这种方式时,我们需要时刻记住如下要点:立即学习“Java免费学习笔记(深入)
”;
1. 无论什么时候这个函数被调用时,它拥有一个特别的变量叫做“this”并且可以在全局范围内使用。全局范围依赖于这个函数自身的作用立即学习“Java免费学习笔记(深入)
”;
范围。
立即学习“Java免费学习笔记(深入)
”;
2. 无论什么时候通过“new”关键字创建这个函数的实例,“this”变量指向这个函数本身,并且这个“new”操作将会影响到函数体中的代立即学习“Java免费学习笔记(深入)
”;
码被执行。这也正是构造模式。
立即学习“Java免费学习笔记(深入)
”;
3. 任何附加到“this”变量下的变量都会成为公有属性并且任何通过“var”关键字定义的变量都将是属于私有属性。
立即学习“Java免费学习笔记(深入)
”;
4. 一个附加到“this”下的函数叫做特权函数,它可以访问所有的私有变量以及被附加到“this”下的函数及变量。
立即学习“Java免费学习笔记(深入)
”;
5. 私有函数可以访问到其他私有变量及私有函数。
立即学习“Java免费学习笔记(深入)
”;
6. 私有函数不能直接访问被附加到“this”变量和函数。我们可以通过创建一个私有变量“_that”并且将它赋值为“this”的方式实现。
立即学习“Java免费学习笔记(深入)
”;
7. 任何私有变量及函数对于其他私有函数及其他被附加到“this”的函数是可用的。这完全是可能的再javascript的作用范围下。
立即学习“Java免费学习笔记(深入)
”;
8. 一个变量:不是通过“var”关键字,也不是附加到“this”变量上以获得全局作用范围的。例如,对于一个自定义函数的作用范围。需要立即学习“Java免费学习笔记(深入)
”;
再一次地了解作用域及集群的知识。
立即学习“Java免费学习笔记(深入)
”;
这已经实现了我们想要的大部分要求了,但是,有时候“this”和“that”这两个入口变量很容易造成给人们带来疑惑。尤其对于那些一直坚立即学习“Java免费学习笔记(深入)
”;
持要求纯粹私有的人来说,更容易迷惑。
立即学习“Java免费学习笔记(深入)
”;
让我们再稍微修改下试试吧。
立即学习“Java免费学习笔记(深入)
”;
[javascript]var Person = function () {//private var firstName = 'John';var lastName = 'Cody';var fullName = '';var message = '';var createFullName = function () {fullName = firstName + ' ' + lastName;}//public setters var setMessage = function (msg) {message = msg;}var setFirstName = function (fName) {firstName = fName;}var setLastName = function (lName) {lastName = lName;}var getMessage = function () {使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更下载createFullName();return message + ' ' + fullName;}//functions exposed public return {setFirstName: setFirstName,setLastName: setLastName,setMessage: setMessage,getMessage: getMessage};};var person1 = new Person();person1.setFirstName('Eli');person1.setLastName('Flowers');person1.setMessage('welcome');var message = person1.getMessage(); // welcome Eli Flowers alert(message);立即学习“Java免费学习笔记(深入)
”;
这是一个显示模式(Revealing Pattern)。非常感谢 Christian Heilmann。使用这种模式的方式就是把请求的"getters" 和 "setters" 当立即学习“Java免费学习笔记(深入)
”;
作属性使用。我们很多都是从传统的Java编程中找到这样的身影并且很明显地知道实现它其实并不复杂。这同样是一种类似于当类继承自一个立即学习“Java免费学习笔记(深入)
”;
接口的情况。
立即学习“Java免费学习笔记(深入)
”;
这种模式大部分方面都实现得很好,仅仅只有一个很微小的问题。每一次当一个类的实例被创建时。这个新创建的对象获得了一份变量和函数立即学习“Java免费学习笔记(深入)
”;
的拷贝。现在,拷贝变量是没有问题的,我们希望对于每一个对象的数据都是属于对象自身的,那么,成员函数呢?他们仅仅是操作数据而已立即学习“Java免费学习笔记(深入)
”;
。那么,为什么需要拷贝他们呢?
立即学习“Java免费学习笔记(深入)
”;
这正是原型模式(Prototype)的优势所在。在所有实例中,所有东西都是被创建成一个原型,并且能够相互分享。我们仅仅需要做的就是依立即学习“Java免费学习笔记(深入)
”;
据原型创建共有函数。
立即学习“Java免费学习笔记(深入)
”;
[javascript]var Person = function () {//private var welcomeMessage = 'welcome';var fullName = '';var firstName = '';var lastName = "";var createFullName = function () {Person.prototype.setFirstName('asdsad');fullName = firstName + ' ' + lastName;};//constructor var Person = function () { }; //will be created evrytime//public Person.prototype = {getFullName: function () {createFullName();return welcomeMessage + ' ' + fullName;},setFirstName: function (fName) {firstName = fName;},setLastName: function (lName) {lastName = lName;},ChangeMessage: function (mesg) {welcomeMessage = mesg;}}return new Person(); // Person; //new Person();};var person1 = new Person();person1.setFirstName ('Eli');person1.setLastName('Flowers');person1.ChangeMessage('welcome');var message = person1.getFullName(); // welcome asdsad Flowers alert(message);立即学习“Java免费学习笔记(深入)
”;
原型模式存在的一个问题是它不能访问私有变量及私有函数,正因为这个问题,我们才会介绍闭包以及始终组织好创建类中存在的代码以使得立即学习“Java免费学习笔记(深入)
”;
它在全局范围内不会变得很混乱。所有都是属于 Person 类的作用范围内。
立即学习“Java免费学习笔记(深入)
”;
另外一个问题是每一次实例被创建时,全部的代码都被执行一遍,包括原型的绑定。对于我们中的一部分人来说,这仅仅只是一个效率问题。
立即学习“Java免费学习笔记(深入)
”;
处理好这个问题的一种方式是仅仅在期望共有函数不可用的情况下绑定这个原型。
立即学习“Java免费学习笔记(深入)
”;
这样将会使得绑定原型操作只会在第一个实例被创建时执行,并且在那之后所有其他的实例都将只会进行检查操作。不幸的是,这样还是不能立即学习“Java免费学习笔记(深入)
”;
解决我们在上面例子中提到的问题,因为我们只有重新再来一次创建的函数用于生成一个闭包来达到这个类的效果。这样的话,至少我们减少立即学习“Java免费学习笔记(深入)
”;
了一部分内存的使用。
立即学习“Java免费学习笔记(深入)
”;
等等,还有另外一个问题是私有函数不能直接访问原型函数。
立即学习“Java免费学习笔记(深入)
”;
为什么你们一定得需要私有函数和私有变量呢?我知道你一定是想实现类的封装性,想确保类中的属性或者内部的数据不会被突然地修改了或立即学习“Java免费学习笔记(深入)
”;
者被内部的其他程序所修改,或者任何其他的操作……
立即学习“Java免费学习笔记(深入)
”;
你应该记住你是不能将 javascript 代码编译成二进制的,对于这种情况,你在一定程度上很恼火吧,这样代码始终都是可用的。所以,如果立即学习“Java免费学习笔记(深入)
”;
任何人想搅乱代码的话,不管你真正实现私有或者没有实现私有,不管你将代码给团队中的其他成员或者卖出去,他们都可以搅乱代码。实现立即学习“Java免费学习笔记(深入)
”;
私有化可能有那么一点点帮助吧。
立即学习“Java免费学习笔记(深入)
”;
另一个其他编程者使用的技术是使用约定命名,使用下划线 “_”给所有你想设成私有任何的东西加上前缀以规定它成为私有。
立即学习“Java免费学习笔记(深入)
”;
[javascript](function () {var Person = function () {this._fullName = '';this.welcomeMessage = '';this.firstName = '';this.lastName = "";_that = this;this._createFullName = function () {this.ChangeMessage('Namaste');this._fullName = this.firstName + ' ' + this.lastName;};}//Shared Functions for Code optimization Person.prototype = {constructor: Person,getFullName: function () {this._createFullName();return this.welcomeMessage + ' ' + this._fullName;},ChangeMessage: function (mesg) {this.welcomeMessage = mesg;}}this.Person = Person;})();var person1 = new Person();person1.firstName = 'Eli';person1.lastName = 'Flowers';person1.ChangeMessage('Welcome');var message = person1.getFullName(); // Namaste Eli Flowers alert(message);立即学习“Java免费学习笔记(深入)
”;
我不是说你不应该考虑 “private” 或者类似的知识。你是代码的设计者,所以你将知道怎么来管理并且知道怎么做才是最好的。根据你的立即学习“Java免费学习笔记(深入)
”;
需求,你可以使用任何一种设计模式或者多个设计模式组合一起使用。
立即学习“Java免费学习笔记(深入)
”;
无论你决定采用哪种设计模式,始终记住做尽量少的事情,不要在全局作用范围内实现闭包,尽量减少内存泄露,以及优化代码,并且组织好立即学习“Java免费学习笔记(深入)
”;
代码。所以,尽量多了解些作用域,闭包以及 “this” 的表现行为。
立即学习“Java免费学习笔记(深入)
”;
最后,祝编程愉快!
译后感经常使用 javascript,对于它的印象一直都是直接拷贝过来就可以用的。最近使用 extjs,它的类框架非常好用。从这样文章也明白在javascript 中实现类的各种方式,以及在文章最后讨论了类中私有成员的实现情况。
