`
driftcloudy
  • 浏览: 132064 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

DOJO中的面向对象__第一章 JS中的对象模型

    博客分类:
  • Dojo
阅读更多

DOJO中的面向对象

 

  在JS中并没有Java等面向对象语言中常见的类(class)的概念。也就是说,JS中的对象并非基于类的。它仅仅为开发者提供了一些原类型和基本的内置对象。从写法上来看,它更加的类似于面向过程式的语言,函数仿佛成了JS中的顶级实体。事实上,JS是一门函数式编程的语言。所以当我们需要以面向对象的方式来构建大型web应用时,原生态的JS并不能很好的满足这一点。而DOJO的出现完美的解决了这个问题,它使得程序员能够以传统的面向对象的思维来进行开发,进而使JS用起来更加得心应手。

 

第一章 JS中的对象模型

(一) 构造器(伪类)

  在JS中创建一个对象很容易,JS提供了语法糖允许我们以字面量的方式来构建对象。例如:

var foo={	'name':'Jack' }

 

  但是在JS中构建一个类却显得稍微复杂。由于JS并没有从语言层面上支持任何自定义类型,所以我们只能通过模拟的方式来构建出一个类。这得益于JS中的强大的函数以及原型机制。先来看一个简单的例子:

function Foo(){
	this.name='Jack';
}
var foo=new Foo();
console.log(foo.name) // 输出jack

 

  在这个例子中,Foo已经不仅仅是一个简单的函数了,我们将Foo看成一个‘伪类’(在javascript中称为构造器)。因此可以用new运算符来生成该类型的对象。通常JS中的类型构造都采用该方法。新生成的对象将自动拥有‘伪类’中定义的字段,所以此例中生成的foo将拥有name属性。

 

  注意Foo中的this.name='Jack'。由于JS中的某些不良设计,一般的函数调用会将该函数中的this绑定到全局对象上,这使得this的使用容易造成混乱。通常而言,如果并不涉及到面向对象编程,可以不必使用this。只有存在了某个对象,this的使用才会有意义。


  如果对构造器进行new运算,构造器中的this会被绑定到生成的新的对象。换句话说,上例中new Foo()时,Foo中的this会被绑定到新生成的实例foo。可以猜测,对一个Foo调用new运算符的时候,会发生类似于下面的过程: 

var obj=new Object();	//obj是一个新生成的对象
Foo.apply(obj);			//将Foo中的this绑定到obj
var foo=obj;			//最后将obj引用返回给foo
 

(二) prototype是什么

  JS中的继承有点特殊,在JS中并不存常见的基于类的继承。JS中的继承是对象与对象之间的行为。也就是说,一个对象可以直接继承另一个对象里的属性。而这一切,都是依靠prototype来完成的。示例如下:

var foo={
	'name':'Jack'
}
function Bar(age){
	this.age=age;
}
Bar.prototype=foo;
var bar=new Bar(22);

 

  这个例子中,我们首先创建了一个对象foo,它包含一个name属性。然后我们创建了一个构造器Bar,由于将Bar当做类来使用,所以将其首字母大写。随后我们将Bar的原型指向foo对象。接着,我们以new的方式来创建了一个Bar的实例bar。很显然,对象bar中包含了两个属性,name属性值为Jack,还有age属性,值为22。值得考究的是Bar. prototype=foo这一句。该语句将Bar的原型设定成一个对象foo。这一句的运行结果是通过Bar创建的所有对象都将继承foo对象的属性。于是,接下来bar便从foo中继承了name属性。

 

  推广开来说, JS中的每个构造器都有一个prototype属性。JS里的构造器,除了包括了我们上面自己定义的‘伪类’,还包括了内置的Object、Function、String 、Array、Number、Date、RegExp等等一系列函数。prototype本身也是一个对象,也就是我们所说的原型对象,如果我们用构造器创建了一个新的对象,该对象便与原型对象发生了继承关系。注意,JS中的继承是发生在两个对象之间的关系,而JAVA之中的继承是两个类之间的关系。


  JS中的继承有两个突出的特点,一是动态性,二是对修改封闭。下面的例子阐述了这两点,例一:

var foo={ 'name':'Jack' }			
function Bar(age){
	this.age=age;
}			
Bar.prototype=foo;			
var bar=new Bar(22);
console.log(bar.name)    //Jack
foo.name='Mike';
console.log(bar.name)    //Mike

 

  当我们修改了foo的属性时,通过bar来访问这些属性也会收到影响。也就是说,我们可以将一些需要的特性动态添加到JS的对象中。这是一种非常强大的编程技术。比如JS中的String对象缺少trim方法。通过

String.prototype.trim=function(){//dojo中的实现
  return this.replace(/^\s\s*/,'').
  replace(/\s\s*$/,'');
} 

 

语句,可以为所有的string加上trim方法。

例二:

var foo={ 'name':'Jack' }
function Bar(age){
	this.age=age;
}
Bar.prototype=foo;
var bar=new Bar(22);
bar.name='Mike';
console.log(bar.name)    // Mike
console.log(foo.name)    // Jack

 

  从上例中可以清楚的看出,如果我们试图通过修改bar来影响foo,这样是行不通的。通过bar可以访问foo的属性,但是却无法改变这些属性的值。当我们修改bar.name='Mike'之后,foo的name值依然是Jack。

 

(三) 原型链(prototype chain)

  事实上,在bar对象中,有一个看不见的_proto属性。该属性指向了Bar.prototype,也就是foo。在Ecma-262 3rd Edition中有如下描述:

写道
Each constructor has a Prototype property that is used to implement prototype-based inheritance and shared properties.
写道
Every constructor has an associated prototype, and every object created by that constructor has an implicit reference to the prototype associated with its constructor.

 

  这段话的意思是JS中的构造器都拥有一个prototype属性。每个由构造器创建出来的object都含有一个指向该prototype的隐式引用。

function Foo(){
	this.name='Jack';
}
var foo=new Foo();
function Bar(age){
	this.age=age;
}
Bar.prototype=foo;
var bar=new Bar(22);

 

因此,上例可以表示成:

 

  注意绿色虚线框内的部分。通过_proto,可以将许多对象串起来,形成一个链条,也就是我们经常说的原型链(prototype chain)。当我们试图访问对象中的一个属性,首先会在对象本体中寻找该属性。如果没有找到,JS会自动在该对象的原型对象中查询该属性,这个过程是一种上溯。如果还是没有找到,会继续上溯到原型对象的原型对象中。


  但是这个步骤不是无止尽的,这个上溯的过程直到Object.prototype._proto为止。以上面的图为例,从foo可以找到的原型对象是Foo.prototype。Foo.prototype本身是一个对象,也是Object的一个实例,因此有:Foo.prototype._proto=Object.prototype 。


  所以在向上追溯的过程中,会追溯到Object.prototype这个对象。如果依然没有我们要找的属性,那还会继续向上追溯么?从Ecma-262 3rd Edition15.2.4节中可以得知:

写道
The value of the internal [[Prototype]] property of the Object prototype object is null and the value of the internal [[Class]] property is "Object".

 

  也就是说Object.prototype._proto=null.至此,可以清楚的弄明白,整个原型链的最顶端的对象是Object.prototype,再往上就是null了。所以原型链可以认为是众多对象利用_proto串成的引用链,有点类似单链表,引用链的最后一个节点是Object.prototype。

 

(四) 维护constructor

  只有当我们创建一个函数(JS中的函数也是对象)时,会自动为这个函数附上prototype对象, prototype中的所有属性会被遗传到该函数创建的对象上。在prototype的属性中,比较特殊的是constructor,constructor的值就是这个函数本身。赋上prototype对象的这个过程类似于:

Foo.prototype={
	constructor:Foo
}

 

如果我们执行:

Foo.prototype.constructor===Foo

 

会输出true。同样如果在Bar.prototype = foo语句之前执行:

Bar.prototype.constructor===Bar

 

也会输出true。由于在prototype对象中的属性会被继承,因此foo和bar中都能访问到constructor属性,分别指向Foo和Bar。

 

  可以看出,JS中的constructor好比JAVA中的Class,在JAVA中一个对象可以通过getClass方法来获取自己的Class,那么JS中的对象可以直接访问constructor来获取自己的构造器。在多层次的继承问题上,我们可能需要维护正确的继承结构。由于无法访问_proto属性,因此继承链的维护只能依靠constructor属性。

function Foo(){}
var foo=new Foo();
function Bar(){}
Bar.prototype=foo;
var bar=new Bar();
console.log(bar.constructor) //Foo

 

  运行上面这个例子,最后的输出结果为Foo。原因是foo中的constructor指向了Foo,而bar又从foo对象继承了该属性。这个时候需要进行一些修改,使得bar的constructor属性能够正确指向Bar。一般有两种方式来处理这个问题。一是在构造器里面修改constructor的值,第二种是在构造完成之后进行修改。

function Foo(){}
var foo=new Foo();
function Bar(){
	this.constructor=Bar;
}
Bar.prototype=foo;
var bar=new Bar();
bar.constructor //Bar 
function Foo(){}
var foo=new Foo();
function Bar(){}
Bar.prototype=foo;
var bar=new Bar();
bar.constructor= Bar;

 

  如果使用下边一种方式,每次实例化一个Bar的对象,都要进行修改。推荐使用上边的方式来修改constructor属性,此修改会对所有Bar的实例生效。

 

3
0
分享到:
评论

相关推荐

    dojo_part001_001_001

    dojo_part001_001_001dojo_part001_001_001dojo_part001_001_001

    dojo_part003_003_003

    dojo_part003_003_003dojo_part003_003_003dojo_part003_003_003

    Dojo-China.zip_chinadojo1688_dojo_dojo 实战_dojo中文网

    8. **dojo/Stateful**: 是一个基类,用于实现具有状态的对象,常见于Dojo的组件中,如dijit/_WidgetBase。 9. **dijit**: dijit是Dojo的UI组件库,包含了一系列可复用的、响应式的、易于定制的界面元素,如按钮、...

    使用_Dojo_的_Ajax_应用开发进阶教程

    JavaScript使用原型链实现面向对象编程中的继承机制。 - **prototype**: 每个函数都有一个 `prototype` 属性,用于指定实例化对象的默认属性和方法。 - **__proto__**: 每个对象都有一个 `__proto__` 属性,指向它...

    Dojo.GUI_v6.zip for pencil

    在设计界,Dojo Toolkit是一个强大的JavaScript库,提供了丰富的UI组件和工具,适用于构建复杂的Web应用程序。Dojo GUI v6模板则将这些组件以可拖拽的形式集成到Pencil中,使得非编码人员也能方便地利用这些专业级别...

    dojo学习001_20101122

    dojo学习001_20101122.dojo学习文件

    使用_Dojo_Mobile_为_iOS_智能终端开发_Native-like_Web_应用

    例如,Dojo Mobile中的Container Widget就是一种管理其他部件如何在不同屏幕尺寸和方向下显示的工具,它能够帮助开发者处理视区变化导致的布局问题。 总之,随着智能手机和移动设备的普及,为这些设备开发Native-...

    提高基于 Dojo 的 Web 2_0 应用程序的性能

    在开发Web 2.0应用程序时,Dojo作为一个强大的JavaScript库,提供了丰富的功能和组件,帮助开发者构建交互式和高性能的网页应用。然而,随着应用复杂性的增加,性能优化成为了一个不可忽视的话题。本文将深入探讨...

    Dojo中文手册_IT168文库.pdf

    Dojo是一个完整的JavaScript工具包,它不仅仅是一个库,而是一个能够帮助开发者构建JavaScript应用的框架。Dojo提供了一整套的工具和组件,包括集合数据结构、加密API、日期处理、拖放操作和事件处理等,从而简化了...

    dojo js dojo js

    dojo js dojo js dojo js dojo js dojo js dojo js dojo js

    dojo中文文档-dojo手册

    《dojo中文文档-dojo手册》提供了全面而深入的Dojo框架知识,这是一份非常有价值的资源,对于想要理解和掌握Dojo JavaScript库的开发者来说至关重要。Dojo是一个强大的JavaScript工具包,它提供了丰富的功能,包括...

    dojo dojo实例 dojo例子 dojo资料 dojo项目 dojo实战 dojo模块 dojo编程

    Dojo 是一个强大的JavaScript工具库,它为Web开发提供了丰富的功能和组件,涵盖了从DOM操作、事件处理到AJAX通信等多个方面。Dojo的核心在于它的模块化系统,这使得开发者可以按需加载代码,提高应用的性能和可维护...

    DOJO_API_中文参考手册 附加注释实例

    Dojo API中文参考手册是一个面向初学者的指导性文件,它详细介绍了Dojo框架的体系结构、常用包及功能,并通过附加注释实例帮助开发者理解和使用Dojo。以下是根据给定内容整理的知识点: 1. Dojo体系架构分层: - ...

    Dojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库

    dojo.js.核心jsDojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库Dojo.js核心dojo的javaScript类库

Global site tag (gtag.js) - Google Analytics