锁定老帖子 主题:基于对象的JavaScript编程2
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-11-25
基于对象的JavaScript编程(2) -JavaScript Object-Oriented Programming
在第一部分中,我们已经讨论了对象,对象方法以及对象的类别,现在我们继续。 参数 任何的方法中,一个私有的变量:argument(js自动创建),以数组的形式保存了传道该方法的所有参数。例如: testArg("PageResource","SitePoint","JavaScriptCity", "WebSite Abstraction"); 来逐个弹出对话框来显示一些我喜爱的web开发站点。
function Person(lastName, firstName){ this.lastName = lastName; this.firstName = firstName; } 接着,来创建一些person的对象: var DnnyGdmn = new Person("Goodman","Danny"); var DvdFlngn = new Person("Flanagan","David"); var TmMyrs = new Person("Myers","Tom"); var AlxNkmvsky = new Person("Nakhimovsky","Alexander"); 然后,就要创建我们的book类。他需要包含如下属性: title pages price author(s) 其中一本书可以有多个作者,所以呢我们就需要接受一到多个person对象做为作者。这样,我们就用一个数组来保存书的作者列表。 function Book(title, pages, price){ this.title = title; this.pages = pages; this.price = price; this.authors = new Array(arguments.length-3); for(i=0;i<arguments.length-3;i++){ this.authors[i] = arguments[i+3]; } } 这段代码前半部分很普通,但后面的可能就不是那么直观了。下面详细解析一下这部分:
this.authors = new Array(arguments.length-3); 这行为book类添加了一个author属性:一个数组对象。调用book()这个构造方法的时候前三个参数分别是title,pages和price,这样后面的参数就是作者信息了。显然,如果传入五个参数,剩下的两个参数就必须是作者。这样创建一个长为arguments.length-3. 的数组也就顺理成章了不是?! arguments.length-3. for(i=0;i<arguments.length-3;i++){ this.authors[i] = arguments[i+3]; } 这段代码遍历了参数中的作者信息,然后逐个添加到作者数组中,下面具体看看怎么创建一个book对象:
var JavaNut = new Book("Java Foundation Classes in a Nutshell", 731, 29.95, DvdFlngn); var JSTDR = new Book("Javascript: The Definitive Guide (3rd Edition)", 776, 39.95, DvdFlngn); var JSBible = new Book("Javascript Bible, 4th Edition", 1200, 49.99, DnnyGdmn); var DHTMLTDR = new Book("Dynamic Html: The Definitive Reference", 1073, 44.95, DnnyGdmn); var JSObj = new Book("JavaScript Objects", 450, 39.99, TmMyrs, AlxNkmvsky); 可以看到我们在建book对象时传入的后面几个参数都是person类型的对象。面向对象的设计方法里有一条原则是避免重复。因此我们就为每个作者建了一个person对象。这样,即使David Flanagan可能写了不止一本书,但是始终指向的都是同一个人。另外如果他想把他的姓改为Behop的话,也只需要把他对应的对象的属性改掉就可以了,而不用找到他写的每一本书逐个改掉。其实上,那些基本数据类型参数我们也可以用对应对象实例替换掉,title属性可以传入一个String型的对象,页数也可以传入Number型对象,但是在这里这样做并没有什么必要,用基本数据类型就完全可以满足需求。 下面继续讨论最难得一个构造函数,Library构造函数。他比较复杂,我们分成几部分来探讨: function Library(){ this.books = new Array(arguments.length); for(i=0;i<arguments.length;i++){ this.books[i] = arguments[i]; } 你可能已经注意到这个方法没有显式的参数定义。你说这是为什么呢?-。- 。实际上因为图书馆只接受book类型的对象,但是我们又不知道有多少本书,所以就只能通过别的方式来定义以及取得参数了。可以看到我们定义的books数组属性,他就是用来保存这些book信息的,那个循环应该不用赘述了吧。如果你想去的一本书的第一作者,就可以这样: this.books[bookIndex].authors[0] 首先取到图书馆的book数组属性。然后得到一个具体的book对象。然后就可以取到这本书的authors属性,在这个数组中包含了该书的所有作者。最后得到的是作者数组中的一个具体person对象。从这个对象里可以得到它的firstName和lastName属性。那个bookIndex是我们想得到的书的索引。 上面的book数组就是我们的library类的所有属性了。剩下的就是方法了: this.totalPrice = function(){ var totalCost = 0; for(i=0;i<this.books.length;i++){ totalCost += this.books[i].price; } return totalCost; } 这个方法遍历了books数组中的所有书籍,取到他们的价格信息并进行了累加然后返回。
this.averagePrice = new Function("return this.totalPrice ()/this.books.length"); 这个方法一看就明白了,取library中所有书籍的平均价。同时我们可以用下面的方法在已经建好的library对象中添加新的book。 this.addBook = new Function("book", "this.books.push(book)"); 这里用了Array的内建方法:push()。这个方法在对应的Array对象上添加新值并同时更新它的length属性。下面我们来建一个显示图书管中所有作者名字的方法。这个方法比较长,分开来讲解: this.getAuthors = function(){ var toSay = "Your favorite authors are:\n"; 这段代码创建一个用来取出作者列表的方法。变量toSay用来做返回值用。
for(i=0;i<this.books.length;i++){ for(j=0; j<this.books[i].authors.length; j++){ var authName = this.books[i].authors[j].firstName + " " + this.books[i].authors[j].lastName; 这段代码也不难,两层循环取到当前作者的firstName和lastName放到了一个新的局部变量authName中。 if(toSay.indexOf(authName)!=-1) continue; toSay+="\n\t"+authName; 如果在toSay中已经存在当前person的信息,就跳过他继续循环取其他的作者信息,否则就将他的信息累加到toSay中。 } } return toSay; } } 最后完成循环,返回结果,方法结束。下面把代码放到一块看看,然后建一个Library实例:
// define our Person() constructor function Person(lastName, firstName){ this.lastName = lastName; this.firstName = firstName; } // define our Book() constructor function Book(title, pages, price){ this.title = title; this.pages = pages; this.price = price; this.authors = new Array(arguments.length-3); for(i=0;i<arguments.length-3;i++){ this.authors[i] = arguments[i+3]; } } //define our Library() constructor function Library(){ this.books = new Array(arguments.length); for(i=0;i<arguments.length;i++){ this.books[i] = arguments[i]; }
this.totalPrice = function(){ var totalCost = new Number(0); for(i=0;i<this.books.length;i++){ totalCost += this.books[i].price; } return totalCost; }
this.averagePrice = new Function("return this.totalPrice()/this.books.length");
this.addBook = new Function("book","this.books.push(book)");
this.getAuthors = function(){ var toSay = "Your favorite authors are:\n"; for i=0;i<this.books.length;i++){ for(j=0;j<this.books[i].authors.length;j++){ var authName = this.books[i].authors[j].firstName + " " + this.books[i].authors[j].lastName; if(toSay.indexOf(authName)!=- 1)continue; toSay+="\n\t"+authName; } } return toSay; } } // create some Person objects DnnyGdmn = new Person("Goodman","Danny"); DvdFlngn = new Person("Flanagan","David"); TmMyrs = new Person("Myers","Tom"); AlxNkmvsky = new Person("Nakhimovsky","Alexander"); // create some Book objects JavaNut = new Book("Java Foundation Classes in a Nutshell",731,29.95,DvdFlngn); JSTDR = new Book("Javascript: The Definitive Guide (3rd Edition)",776,39.95,DvdFlngn); JSBible = new Book("Javascript Bible, 4th Edition",1200,49.99,DnnyGdmn); DHTMLTDR = new Book("Dynamic Html: The Definitive Reference",1073,44.95,DnnyGdmn); JSObj = new Book("JavaScript Objects",450,39.99,TmMyrs,AlxNkmvsky); // create a Library object myLib = new Library(JavaNut,JSTDR,JSBible,DHTMLTDR);
Oops(老外的一种感叹词,。。。),拉掉了一个book对象,最好还是加上吧:(老外就喜欢搞这一套,你要是看过《Head First Design Pattern》这本书的话,相信对这一套也会跟我一样有点胃不是很舒服了。。。) myLib.addBook(JSObj); Ok,大功告成,你可以取得诸如图书馆书籍总价,均价,所有作者名等信息。看到了吧,我们用JavaScript建立了一个完全面向对象的例子。(下面广告时间 跳过 -.-)
Prototype (这个词也许可以翻译成:原型)
所有的对象构建器(也许说成对象更好)都有这个特殊的属性:prototype。通过它你可以给使用相同构造器创建的对象添加属性/对象。有点晕乎吧,先来看个例子相信你就精神了: function Square(){ } var squareObj = new Square(); Square.prototype.side = 5; var squareObj2 = new Square(); alert(squareObj.side); // displays 5 alert(squareObj2.side); // displays 5 看到了吧,上面代码中我们在Square的实例对象中的prototype属性上添加了一个side属性,初始值为5.然后其他的对象也都有了这个属性。需要注意的是prototype对象(实际上它就是一个对象)在对象的构造函数执行之前首先加载。又有点晕吧 呵呵,继续看代码: function Square(){ this.side=5; } var squareObj = new Square(); Square.prototype.side = 4; var squareObj2 = new Square(); alert(squareObj.side); // displays 5 alert(squareObj2.side); // displays 5 看到了没,返回值是5而不是4.现在上面那句话应该明白了吧,prototype首先加载。即使Square对象构造器已经运行过,然后你又再prototype上添加或者更新了属性,最终还是会被构造器中的内容覆盖掉(个人理解,只要你更改了prototype,对应对象的构造器就会自动执行一遍)。下面的例子里我们使用了String对象的prototype属性来给String添加新的方法: function consonantize(){ var consonants =""; for(i=0;i<this.length;i++){ var l = this.charAt(i); if(l!="a" && l!="A" && l!="e" && l!="E" && l!="i" && l!="I" && l!="o" && l!="O" && l!="u" && l!="U" && l!=" "){ consonants+=l; } } return consonants; }
这个方法逐个字符遍历当前String 然后去除所有的原音或者空字符,只返回了剩下的辅音。这样我们就可以在所有的String的实例对象里或者基础类型里使用它了:
String.prototype.consonantize = consonantize; var dg = "Danny Goodman"; var df = new String("David Flanagan"); alert(dg.consonantize()); alert(df.consonantize()); Neat, huh?(嘿嘿,呵呵,哈哈。。。。),在String类型实例里或者String基础类型中尼都可以像使用任何其他方法一样去使用这个新方法了。 总结一下:我们可以在JavaScript内建对象上的prototype上添加任何想加的方法,这跟使用我们自己定义的对象是一样的。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 1678 次