JavaScript 面向对象编程Object. defineProperties( chenhaocmailvaluc: haocl hotmail comtrueconfigurable: true,enumerable: truevalue:http://coolshell.cntruconfigurable: trueenumerabletrue下面就说说这些属性配置是什么意思。1、 writable:这个属性的值是否可以改。2、 configurable:这个属性的配置是否可以改。3、 enumerable:这个属性是否能在for…in循环中遍历出来或在0 bject.keys中列举出米。4、 value:属性值、5、getO/set( value):get和set访问器Get/Set访问器关于get/set访问器,它的意思就是用get/set来取代 value(其不能和 value一起使用),示例如下var age =0Ob ject defineRchenhaoget: function( freturn age+1; Iset: function(value):age= value; Jenumerable. trueFigurable: true100;//调用setalert( chenhao.age);/调用get输出101我们再看一个更为实用的例子—利用已有的属性age)通过get和set构造新的属性Object. dcfincPropcrty( chenabirthget: function(dDalevar y=d. getFullYear(return( y- this ageset: function (year)var d= new Date ovar y=d get(this age =y- yearalert(chcnhao birth ycar)chenhao, birth vear =2000alert(chenhao age这样做好像有点麻烦,你说,我为什么不写成卜面这个样子:var chenhao =[il:hagel@hotmail.comwebsite:http://coolshell.cnage.get birth year ivar d= new Dale ovar y=d. getFullYearreturn (y- this ageset birth year(year)var d= new DHLe ovar y-d. gotFullYcar(this age= y-yearalert(chenhao birth yearchenhao, birth vcar=2000alert(chenhao age)是的,你的确可以这样的,不过通过 defineProperty(你可以干这些事1、设置如 writable, configurable, enumerable等这类的属性配置2、动态地为一个对象加属性。比如:一些HTML的DOM对像。查看对象属性配置如果查看并管理对象的这些配置,下面有个程序可以输出对象的属性和配置等东西:/列出对象的属性function listProperties(obj)var newlinevar names= Object. getOwnPropertyNames(obj)for (var i=0[i]document. write(prop newLine)//列出对象的属性配置( descriptor)动用 getOwnPropertyDescriptor函数。var descriptor=Object. getOwnPropertyDescriptor (obj, propfor (var attr in descriptordocument.write("."+ attr+':'+dcscriptorlattrl)document.write(newLine)document. write (newl inelistPronerties(chenhao)call, apply,bind和thi关于 Javascript的this指针,和C|/Java很类似。我们米看个示例:(这个示例很简单了,我就不多说了)function print(text)[document. write(this. value+’-’+text+’1);vara=value: 10, print printvar b-valuc: 20, print printprint(hello'): / this => global, output"undefineda print(a); / this =>a, output10-ab print(b):// this =>b, output20-ba[ print'](a);// this -) a, oulpul10-a我们再米看看ca11和 apply,这两个函数的差别就是参数的样子不一样,另一个就是性能不一样, apply的性能要差很多。(关于性能,可到 JSPerf上去跑跑看看)print. call(a,a);// this=)a, output 10-aprint. call(b,'b);// this =>b, output20-bprint. apply(a,['aD);// this=)a, outputIprint. apply(b, [bD;// this=>b, output20-b但是在bind后,this指针,可能会有不一样,但是因为 JavaScript是动态的。如下面的例var p- prlp(a');// this = a, output10-ap. ca// this=>a, output 10p apply(b, [b'1);// this =)a, output10-a继和重载通过上面的那些示例,我们可以通过 Object. create O来实际继承,请看下面的代码,Student继承于0 bjectvar Person-Object create(null)Ob jcct. dcfincPropcrticsPersonname{ value: Chen hao’},cmail':i valuc: ' haocl hotmail. com'websitevalue:http://coolshel1.cn'jPerson sayHello= function (person) ivar hello =Hello,I am+ this name+my email+this emailmy website is:+ his websitedocument. write(hello +"var student=0 bject. create( Person);//注意这里Student.no="1234567";/学号Student depl="Computer Science";//f//检查 Person的属性document. write(Studentname+ Student. email+’’+ Student. website+2)//检查 Person的方法Student, sayHello o重载 Save11o方法Student. sayHcllo- function (pcrson)var hello =lle llo.i amI this, name IIilmy website isthis website +,tudent no is:+ thdepartent ispdocument. write(hello I')再次调用Student. sayHelloo//查看 Student的属性(只有no、dept和重载了的saye1lo)ocument. wrlte(’| Ob ject..keys( Student)’)通用上面这个示例,我们可以看到, Person里的属性并没有被真正复制到了 Student中来,但是我们可以去存取。这是因为 JavaScript用委托实现了这一机制。其实,这就是 Prototype,Person是 Student的 Prototype当我们的代码需要个属性的时候, JavaScript的引擎会先看当前的这个对象中是否有这个属性,如果没有的话,就会查找他的 Prototype对象是合有这个属性,一直继续下去,直找到或是直到没有 Prototype对象。为了讦明这个事,我们可以使用 Object. getPrototypeOf(来检验一下Student name//输出aaadocument. write(’+ Student.name+’//输出 Chen haodocument. write(' +Object. getPrototypeOf(Student). name +'3)于是,你还可以在子对象的函数里调用父对象的函数,就好像C++里的Base: func O一样。于是,我们重载he1lo的方法就可以使用父类的代码了,如下所示://新版的重载 SahEl10方法Student. say Hello= function (person)0 bject. getPrototypeof(this). sayHello.call(this);//注意这里var hello=my student no is:+ this. no+,+my departent is: this. depldocument. write(hello +''这个很强大吧。组合上面的那个东西还不能满足我们的要求,我们可能希望这些对象能真正的组合起来。为什么要组合?因为我们都知道是这是00设计的最重要的东西。不过,这对于 Javascript来并没有支持得特别好,不好我们依然可以搞定个事。首先,我们需要定义一个 Composition的函数:( target是作用于是对象, Source是源对象)下面这个代码还是很简单的,就是把 source里的属性一个一个拿出来然后定义到 targetfunction Composition(target, source)var dcsc- Obiect. gctOwnPropcrtyDcscriptorvar prop =Object. getOwnPropert yName svar def project. definePropertyprop (source). forEach(Tune lion (key)def prop (target, key, desc(source, key))return target有了这个函数以后,我们就可以这来玩了://艺术家var Artist=Object create(null);Artist. sing- function(return this name t starts singingArtist paint= function( ireturn this name starts painting//运动员var SporTer-ObjecL credLe(null)Sporter. run function Ireturn this name t starts runningSporter. swim= function(return this llame starts swimmingComposition( Person, Artist);//注意这里document. write(Person. sing(+'
')document. write(Person. paint oComposition( Persor, Sporter);//注意这里document. write(Pcrson, run(+
')document. write(Person. swim//看看 Person中有什么?(输出: sayHello,sing, paint,swim,rundocument.write('+ Object keys(Person)+')Prototype和继承我们先来说说 Prototype。我们先看下面的例程,这个例程不需要解释吧,很像C语言里的函数指针,在C语言甲这样的东西见得多了。var plus= function(x, y)tdocument. write(x+’+’+y++y)+return x y;var minus= function(x, y)(document. write(x+return x-yvar opcrationsminuslculate functionn){return operations [operation.(x, y)alculate(12, 4, +)calculatc(24,3,’-)那么,我们能不能把这些东西封装起来呢,我们需要使用 prototype。看下面的示例var Cal= function(x, y)tthis y =yCaL. prototype. operations={//注意这里+ function(x, y)( return x+yfunction(x, y) return x-y: 1Cal. prototype. calculate= Funetion( operatiOnl){//注意这里return this operations [operation](this x, this y)var c= new Cal(4, 5)Cal. calculate(+)Cal. calculate(-)这就是 prototype的用法, prototype是 JavaScript这个语言中最重要的内容。网上有太多的文章介始这个东西了。说白了, prototype就是对一对象进行扩展,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的(当然,这里没有真止的复制,实际只是委托)。上面的这个例子中,我们扩展了实例Cal,计其有了一个 operations的属性和一个 calculatc的方这样,我们可以迸过这一特性来实现继承。还记得我们最最前面的那个 Person吧,下面的示例是创建个 Student来继 Personfunction Person (name, email, website)ithis name= namethis cmail= cmailthis website websitePerson. prototype sayHello= function( ivar hello=Hello,i an+ this naue+mail ismy website isrcturn hellofunction Student (name, email, website, no, dept)ivar proto=Object. getPrototypeof(Student protot ype) constructor call(th1, website)this dept dept//继承 prototypeStudent prototype=Object create(Person. prototype)//重置构造函数StudentinstructStudent//重载 savE1lo()Student prototype. sayHcllo- function (ivar proto =Object. getPrototypeofvar hello= proto(Student. prototype). sayHello call(this)+hello + my student no is:+ this. no+his. deplrcturn hellovar me= new Student(hagel hotmail. comhttp://coolshcll.cn12345678",Computer Sciencedocument. write(me sayHello()兼容性上面的这些代码并不一定能在所有的浏览器下都能运行,因为上面这些代码遵循ECMAScript5的规范,关于 ECMAScript5的浏览器兼容列表,你可以看这里“ES5浏览器兼容表”本文中的所有代码都在 Chrome最新版中测试过了。下面是一些函数,可以用在不兼容ES5的浏览器中:0 bject. create函数function clone (proto)