JAVA培训全面理解面向对象的JavaScript

上传人:简****9 文档编号:53415249 上传时间:2022-02-10 格式:DOCX 页数:7 大小:34.49KB
返回 下载 相关 举报
JAVA培训全面理解面向对象的JavaScript_第1页
第1页 / 共7页
JAVA培训全面理解面向对象的JavaScript_第2页
第2页 / 共7页
JAVA培训全面理解面向对象的JavaScript_第3页
第3页 / 共7页
点击查看更多>>
资源描述
JAVA培训:全面理解面向对象的JavaScript重新认识面向对象为了说明JavaScript是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手探讨一下面向对象中的几个概念: 一切事物皆对象 对象具有封装和继承特性 对象与对象之间使用消息通信,各自存在信息隐藏以这三点做为依据,C+是平面向对象平面向过程语言,因为,虽然他实现了类的封装、继承和多态,但存在非对象性质的全局函数和变量。JavaC#是完全的面向对象语言,它们通过类的形式组织函数和变量,使之不能脱离对象存在。但这里函数本身是一个过程,只是依附在某个类上。然而,面向对象仅仅是一个概念或者编程思想而已,它不应该依赖于某个语言存在。比如Java采用面向对象思想构造其语言,它实现了类、继承、派生、多态、接口等机制。但是这些机制,只是实现面向对象编程的一种手段,而非必须。换言之,一门语言可以根据其自身特性选择合适的方式来实现面向对象。所以,由于大多数程序员首先学习或者使用的是类似JavaC+等高级编译型语言(Java虽然是半编译半解释,但一般做为编译型来讲解),因而先入为主地接受了类”这个面向对象实现方式,从而在学习脚本语言的时候,习惯性地用类式面向对象语言中的概念来判断该语言是否是面向对象语言,或者是否具备面向对象特性。这也是阻碍程序员深入学习并掌握JavaScript的重要原因之一。实际上,JavaScript语言是通过一种叫做原型(prototype)的方式来实现面向对象编程的。下面就来讨论基于类的(class-based面向对象和基于原型的(prototype-based)面向对象这两种方式在构造客观世界的方式上的差别。基于类的面向对象和基于原型的面向对象方式比较在基于类的面向对象方式中,对象(object)依靠类(clas来产生。而在基于原型的面向对象方式中,对象(object)则是依靠构造器(constructor)利用原型(prototype)构造出来的。举个客观世界的例子来说明二种方式认知的差异。例如工厂造一辆车,一方面,工人必须参照一张工程图纸,设计规定这辆车应该如何制造。这里的工程图纸就好比是语言中的类(class)而车就是按照这个类(clas制造出来的;另一方面,工人和机器(相当于constructor)利用各种零部件如发动机,轮胎,方向盘(相当于prototype的各个属性)将汽车构造出来。事实上关于这两种方式谁更为彻底地表达了面向对象的思想,目前尚有争论。但笔者认为原型式面向对象是一种更为彻底的面向对象方式,理由如下:首先,客观世界中的对象的产生都是其它实物对象构造的结果,而抽象的“图纸”是不能产生“汽车”的,也就是说,类是一个抽象概念而并非实体,而对象的产生是一个实体的产生;其次,按照一切事物皆对象这个最基本的面向对象的法则来看,类(class)本身并不是一个对象,然而原型方式中的构造器(constructor)和原型(prototype)本身也是其他对象通过原型方式构造出来的对象。再次,在类式面向对象语言中,对象的状态(state)由对象实例(instance)所持有,对象的行为方法(method)则由声明该对象的类所持有,并且只有对象的结构和方法能够被继承;而在原型式面向对象语言中,对象的行为、状态都属于对象本身,并且能够一起被继承,这也更贴近客观实际。最后,类式面向对象语言比如Java,为了弥补无法使用面向过程语言中全局函数和变量的不便,允许在类中声明静态(static)属性和静态方法。而实际上,客观世界不存在所谓静态概念,因为一切事物皆对象!而在原型式面向对象语言中,除内建对象(build-inobject)外,不允许全局对象、方法或者属性的存在,也没有静态概念。所有语言元素(primitive)必须依赖对象存在。但由于函数式语言的特点,语言元素所依赖的对象是随着运行时(runtime)上下文(context)变化而变化的,具体体现在this指针的变化。正是这种特点更贴近“万物皆有所属,宇宙乃万物生存之根本”的自然观点。在程序清单1中window便类似与宇宙的概念。清单1.对象的上下文依赖varstr=我是一个String对象,我声明在这里,但我不是独立存在的!varobj=des:我是一个Object对象,我声明在这里,我也不是独立存在的。;varfun=function()console.log(我是一个Function对象!谁调用我,我属于谁:,this);打印 true打印 trueobj.fun=fun;console.log(this=window);/console.log(window.str=str);/console.log(window.obj=obj);/console.log(window.fun=fun);/fun();/obj.fun();/fun.apply(str);/打印 true打印 true打印我是一个Function打印我是一个Function打印 我是一个 Function对象!谁调用我,我属于谁:window对象!谁调用我,我属于谁:obj对象!谁调用我,我属于谁: str在接受了面向对象存在一种叫做基于原型实现的方式的事实之后,下面我们就可以来深入探讨ECMAScript是如何依据这一方式构造自己的语言的。最基本的面向对象ECMAScript是一门彻底的面向对象的编程语言,JavaScript是其中的一个变种(variant)。它提供了6种基本数据类型,即Boolean、Number、String、Null、Undefined、Object。为了实现面向对象,ECMAScript设计出了一种非常成功的数据结构-JSON(JavaScriptObjectNotation),这一经典结构已经可以脱离语言而成为一种广泛应用的数据交互格式。应该说,具有基本数据类型和JSON构造语法的ECMAScript已经基本可以实现面向对象的编程了。开发者可以随意地用字面式声明(literalnotation)方式来构造一个对象,并对其不存在的属性直接赋值,或者用delete将属性删除(注:JS中的delete关键字用于删除对象属性,经常被误作为C+中的delete,而后者是用于释放不再使用的对象),如程序清单2。清单2.字面式(literalnotation)对象声明varperson=name:“张三”,age:26,gender:“男”,eat:function(stuff)alert(“我在吃”+stuff);person.height=176;deleteperson“age”;在实际开发过程中,大部分初学者或者对JS应用没有太高要求的开发者也基本上只用到ECMAScript定义的这一部分内容,就能满足基本的开发需求。然而,这样的代码复用性非常弱,与其他实现了继承、派生、多态等等的类式面向对象的强类型语言比较起来显得有些干瘪,不能满足复杂的JS应用开发。所以ECMAScript引入原型来解决对象继承问题。使用函数构造器构造对象除了字面式声明(literalnotation)方式之外,ECMAScript允许通过构造器(constructor)创建对象。每个构造器实际上是一个函数(function)对象,该函数对象含有一个prototyped性用于实现基于原型的继承(prototype-basedinheritance和共享属性(sharedpropertied。对象可以由“newl键+构造器调用”的方式来创建,如程序清单3:清单3.使用构造器(constructor)创建对象/构造器Person本身是一个函数对象functionPerson()/此处可做一些初始化工作/它有一个名叫prototype的属性Person.prototype=name:“张三”,age:26,gender:“男”,eat:function(stuff)alert(“我在吃”+stuff);/使用new关键字构造对象varp=newPerson();由于早期JavaScript的发明者为了使这门语言与大名鼎鼎的Java拉上关系(虽然现在大家知道二者是雷锋和雷锋塔的关系),使用了new关键字来限定构造器调用并创建对象,以使其在语法上跟Java创建对象的方式看上去类似。但需要指出的是,这两门语言的new含义毫无关系,因为其对象构造的机理完全不同。也正是因为这里语法上的类似,众多习惯了类式面向对象语言中对象创建方式的程序员,难以透彻理解JS对象原型构造的方式,因为他们总是不明白在JS语言中,为什么“函数名可以作为类名”的现象。而实质上,JS这里仅仅是借用了关键字new,仅此而已;换句话说,ECMAScript完全可以用其它非new表达式来用调用构造器创建对象。彻底理解原型链(prototypechain)在ECMAScript中,每个由构造器创建的对象拥有一个指向构造器prototype属性值的隐式引用(implicitreference),这个引用称之为原型(prototype)。进一步,每个原型可以拥有指向自己原型的隐式引用(即该原型的原型),如此下去,这就是所谓的原型链(prototypechain)。在具体的语言实现中,每个对象都有一个_proto_属性来实现对原型的隐式引用。程序清单4说明了这一点。清单4.对象的_proto_属性和隐式引用functionPerson(name)this.name=name;varp=newPerson();/对象的隐式引用指向了构造器的prototype属性,所以此处打印trueconsole.log(p._proto_=Person.prototype);/原型本身是一个Object对象,所以他的隐式引用指向了/Object构造器的prototype属性,故而打印trueconsole.log(Person.prototype._proto_=Object.prototype);/构造器Person本身是一个函数对象,所以此处打印trueconsole.log(Person._proto_=Function.prototype);有了原型链,便可以定义一种所谓的属性隐藏机制,并通过这种机制实现继承。ECMAScript规定,当要给某个对象的属性赋值时,解释器会查找该对象原型链中第一个含有该属性的对象(注:原型本身就是一个对象,那么原型链即为一组对象的链。对象的原型链中的第一个对象是该对象本身)进行赋值。反之,如果要获取某个对象属性的值,解释器自然是返回该对象原型链中首先具有该属性的对象属性值。图1说名了这中隐藏机制:图1.原型链中的属性隐藏机制在图1中,object1-prototype1-prototype2构成了对象object1的原型链,根据上述属性隐藏机制,可以清楚地看到prototype1对象中的property4属性和prototype2对象中的property3属性皆被隐藏。理解了原型链,那么将非常容易理解JS中基于原型的继承实现原理,程序清单5是利用原型链实现继承的简单例子。清单5.利用原型链Horse-Mammal-Animal实现继承/声明Animal对象构造器functionAnimal()/将Animal的prototype属性指向一个对象,/亦可直接理解为指定Animal对象的原型Animal.prototype=name:animal,weight:0,eat:function()alert(Animaliseating!);/声明Mammal对象构造器functionMammal()this.name=mammal;/指定Mammal对象的原型为一个Animal对象。/实际上此处便是在创建Mammal对象和Animal对象之间的原型链Mammal.prototype=newAnimal();/声明Horse对象构造器functionHorse(height,weight)this.name=horse;this.height=height;this.weight=weight;/将Horse对象的原型指定为一个Mamal对象,继续构建Horse与Mammal之间的原型链Horse.prototype=newMammal();/重新指定eat方法,此方法将覆盖从Animal原型继承过来的eat方法Horse.prototype.eat=function()alert(Horseiseatinggrass!);/验证并理解原型链varhorse=newHorse(100,300);console.log(horse._proto_=Horse.prototype);console.log(Horse.prototype._proto_=Mammal.prototype);console.log(Mammal.prototype._proto_=Animal.prototype);理解清单5中对象原型继承逻辑实现的关键在于Horse.prototype=newMammal()和Mammal.prototype=newAnimal()这两句代码。首先,等式右边的结果是构造出一个临时对象,然后将这个对象赋值给等式左边对象的prototype属性。也就是说将右边新建的对象作为左边对象的原型。读者可以将这两个等式替换到相应的程序清单5代码最后两行的等式中自行领悟。
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 商业管理 > 市场营销


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!