第八章 自定义对象

ECMAScript对象是JavaScript比较特殊的特性之一,在JavaScript中,要记住一点,一切都是对象,包括我们前面所学的方法.本章的重点是如何操作及使用这些对象,以及如果创建自己的对象,以根据需要增加专用的功能.

ECMA-262把对象(Ojbect)定义为"属性的无序集合,每个属性存放一个原始值,对象或函数."严格来说,这意味着对象是无特定顺序的值的数组.

每个对象都由类定义,可以把类看作对象的配方,类不仅要定义对象的接口(属性和方法),还要定义对象的内部工作(使属性和方法发挥作用的代码).

面向对象语言的要求:
1.封装:把相关信息(数据或方法)存储在对象中的能力.
2.聚集:把一个对象存储在另一个对象内的能力.
3.继承:由另一个类(或多个类)得来类的属性和方法的能力.
4.多态:编写能以多种方法运行的函数或方法的能力.

ECMAScript支持这些要求,因此可以看作面向对象的.

在ECMAScript中,对象由特性构成,特性可以是原始值,也可以是引用值.如果特性存放的是函数,它将被看作是对象的方法,否则该特性被看作属性.

声明和实例化
var oObject = new Object();
var oStringObject = new String();
如果构造方法无参数,则括号不是必需的.

对象回收
ECMAScript有无用存储单元收集程序,意味着不必专门销毁对象来释放内存,当对象没有引用绑定时,称该对象被废除了.每个函数执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些其它不可预知的情况下,无用存储单元收集程序也会运行.

把对象与null对象绑定,可以强制性的废除对象.
var oObject = new Ojbect();
oObject = null;
每用完一个对象后,就将其废除,来释放内存,是个好习惯.
废除对象的所有引用时要当心,如果一个对象有两个或更多引用,则要正确废除该对象,必须将其所有的引用都设置为null

ECMAScript的封装
对ECMAScript来说,作用域的讨论几乎毫无意义,因为ECMAScript中只存在一种作用域,公用作用域,所有对象的所有属性和方法都是公用的,因此,定义自己的类和对象,必须格外小心,记住,所有属性和方法默认都是公用的.

ECMAScript由于缺少私有作用域,开发者们制定了一个规约,说明哪些属性和方法应该被看作私有的,这种规约规定在属性名前后加上下划线,如:obj._color_ = "red",这段代码告诉我们属性color是私有的,但是下划线并不改变这些属性是公用属性的事实,它只是告诉其他开发者,应该把该属性看作是私有的.

关键字this
ECMAScript中,this总是指向调用该方法的对象.例如:
var oCar = new Object();
oCar.color = "red";
oCar.showColor = function(){
alert(this.color);
}
这里,关键字this用在对象的showColor方法中,在此环境中,this等于oCar,下面的代码与上面的代码功能相同:
var oCar = new Object();
oCar.color = "red";
oCar.showColor = function(){
alert(oCar.color);
}

考虑下面的示例:
function showColor(){
alert(this.color);
}

var oCar1 = new Object();
oCar1.color = "red";
oCar1.showColor = showColor;

var oCar2 = new Object();
oCar2.color = "blue";
oCar2.showColor = showColor;

oCar1.showColor();
oCar2.showColor();

注意引用对象的属性时,必须使用this关键字,例如,下面的showColor方法不能运行.
function showColor(){
alert(color);
}

工厂模式
由于对象的属性可以在对象创建后动态定义,所以许多开发都在初次学习类时,会像上面那样创建对象.这样问题就出来了,如果要创建多个car实例呢,怎么办呢?解决方法工厂模式,请看下面的代码:
function createCar(){
var oTempCar = new Object();
oTempCar.color = "red";
oTempCar.showColor = function(){
alert(this.color);
}

return oTempCar;
}
var oCar1 = createCar();
var oCar2 = createCar();
这样做,有个毛病,就是两个对象的属性完全一样,没有关系,加参数列表,传递各个属性的值.改为:
function createCar(sColor){
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.showColor = function(){
alert(this.color);
}

return oTempCar;
}
var oCar1 = createCar("red");
var oCar2 = createCar("blue");
这时可以看到两个对象具有相同的属性,却有不同的属性值.

前面的例子中,每次调用函数createCar()都要创建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象应该共享同一个函数.

解决方法:在工厂方法外定义对象的方法,然后通过属性指向该方法.从而避开这个问题,请看下面的代码:
function showColor(){
alert(this.color);
}

function createCar(sColor){
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.showColor = showColor;

return oTempCar;
}
var oCar1 = createCar("red");
var oCar2 = createCar("blue");
oCar1.showColor();
oCar2.showColor();
虽然这样做,解决了重要创建函数对象的问题,但该函数看起来不像对象的方法.所有这些问题引发了开发者定义的构造函数的出现.

构造函数方式
创建构造函数就像定义工厂函数一样,定义构造函数名时,根据习惯,首字母大写,以使它与其它的普通方法区分开来.

function Car(sColor){
this.color = sColor;
this.showColor = function(){
alert(this.color);
}
}
var oCar1 = new Car("red");
var oCar2 = new Car("blue");
与前面的差别:构造函数内部无创建对象,而是使用this关键字.

现在用new运算符和类名Car创建对象,就更像创建ECMAScript中一般对象了,但是构造函数会重复生成函数,为每个对象都创建独立的函数版本,不过,与工厂函数相似,也可以用外部函数重写构造函数.
function showColor(){
alert(this.color);
}

function Car(sColor){
this.color = sColor;
this.showColor = showColor;
}
var oCar1 = new Car("red");
var oCar2 = new Car("blue");

更好解决方案:原型方式

原型方式
上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,showColor()方法感觉有点像一个单独的方法,和Car类没有什么固定的关系.

原型对象,大家可以理解为Java中的Class Car{...},也就是类定义的原型代码,定义好构造函数后,JavaScript会自动创建构造函数对应的原型对象,每个构造方法都有一个prototype属性,该属性返回原型对象的引用,我们可以让原型对象绑定类所拥有的方法,让其整个架构看起来更像面向对象的语义.
请看下面的代码:
function Car(sColor){
this.color = sColor;
}
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car("red");
oCar1.showColor();
现在看起来就更像创建一般对象了.这也是现在JS中最流行的创建对象的方式,有个规定,构造函数中规定属性值,方法一律在外面用原型的方式添加.

instanceof 运算符:判断对象的类型
function MyObject(){

}
alert(oCar1 instanceof Car);
alert(oCar1 instanceof MyObject);

修改内置对象
在ECMAScript中,每个本地对象也有用法完全相同的prototype属性.比如,JS中,String类没有提供trim()方法,Java中此方法可以截取字符串两端的空格,那么我们怎么样在JS中创建此方法呢?
String.prototype.trim = function(){
return this.replace(/(^ +)|( +$)/g,"");
}
var str = " AAA ";
alert(str.length);
alert(str.trim().length);

创建自己的实用工具类
StringBuffer类,Java中是字符串缓冲类,具有较高的连接效率,我们在JS中怎么实现这个类呢.比如我们要执行一个字符串的连接操作,如果用+号进行连接,会造成生成许多临时字符串,这样非常消耗资源,会造成性能问题.最好的解决方法是用Array对象存储字符串,然后用join()方法(参数为空字符串"")创建最后的字符串.
function StringBuffer(){
this._strings_ = new Array();
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
}
StringBuffer.prototype.toString = function(){
this._strings_.join("");
}

var d1 = new Date();
var str = "";
for(var i=0; i<1000000; i++ ){
str += "text";
}
var d2 = new Date();
document.write("连+所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
document.write("<BR><BR>");

var oBuffer = new StringBuffer();
d1 = new Date();
for(var i=0; i<1000000; i++ ){
oBuffer.append("text");
}
d2 = new Date();
document.write("StringBuffer所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");

经过测试,怪事发生了,竟然StringBuffer效率要低200%以上.

目标
1.对象的介绍
2.创建对象
3.对象的属性
4.对象的构造函数
5.对象的方法
6.Object对象

对象的理解:它是一种复杂的数据类型,也是一个工具,它能够保存数据,也可以处理数据.

对象创建的三种方法:
1.对象直接量
2.设置属性法
3.构造函数(推荐方式)

[size=large]对象直接量[/size]

var circle = { x:0, y:0, radius:2 }
document.write(circle.x);
document.write(circle.y);
document.write(circle.radius);
--------------------------------------------------------------------
var homer = {
name: "Homer Simpson",
age: 34,
married: true,
occupation: "plant operator",
email: "homer@simpsons.com"
};
document.write(homer.name + "<BR />");
document.write(homer.age + "<BR />");
document.write(homer.married + "<BR />");
document.write(homer.occupation + "<BR />");
document.write(homer.email + "<BR />");

[size=large]设置属性法[/size]

var book = new Object(); //创建一个book对象
book.title = "JavaScript: The Definitive Guide";//给book对象添加一个属性

book.chapter1 = new Object(); //给book对象添加一个chapter1的属性,并且此属性也是对象
book.chapter1.title = "Introduction to JavaScript";//给book.chapter1添加属性
book.chapter1.pages = 19;//给book.chapter1添加属性
//给book对象添加一个chapter2的属性,并且此属性也是对象(对象直接量方式)
book.chapter2 = { title: "Lexical Structure", pages: 6 };

document.write("Outline: " + book.title + "<BR/>" +
"Chapter 1 " + book.chapter1.title + "<BR/>" +
"Chapter 2 " + book.chapter2.title);
[size=large]

[size=large]构造函数[/size]

function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
var rect2 = new Rectangle(8.5, 11);
document.write(rect1.width + "," + rect1.height + "<BR />");
document.write(rect2.width + "," + rect2.height + "<BR />");

[size=large]属性的枚举[/size]

function DisplayPropertyNames(obj) {
for(var name in obj){
document.write(name + "<BR />");
}
}

function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);

DisplayPropertyNames(book);

[size=large]属性的删除[/size]

function DisplayPropertyNames(obj) {
for(var name in obj){
document.write(name + "<BR />");
}
}

function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
delete rect1.width;
DisplayPropertyNames(rect1);

[size=large]给对象添加方法[/size]

//先准备好方法,注意这里用到了this关键字
function Rectangle_area( ) { return this.width * this.height; }
function Rectangle_setSize(w,h) { this.width = w; this.height = h; }

function Rectangle(w, h){
this.width = w;
this.height = h;

//添加方法,将方法绑定到属性上
this.area = Rectangle_area;
this.setSize = Rectangle_setSize;
}
var rect1 = new Rectangle(2, 4);
document.write(rect1.area() + "<BR />");
rect1.setSize(20,40);
document.write(rect1.area());

[size=large]构造函数创建对象的缺点[/size]

用构造函数把方法赋予它要初始化的对象,效率非常低,如果我们这样做,那么构造函数创建的每一个对象都会有相同的方法属性的副本。
我们的目标是:类所声明的方法,常量能够被所有的对象共享。

解决方法:原型对象和继承

[size=large]原型方式[/size]

上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,showColor()方法感觉有点像一个单独的方法,和Car类没有什么固定的关系.
原型对象,大家可以理解为Java中的Class Car{...},也就是类定义的原型代码,定义好构造函数后,JavaScript会自动创建构造函数对应的原型对象,每个构造方法都有一个prototype属性,该属性返回原型对象的引用,我们可以让原型对象绑定类所拥有的方法,让其整个架构看起来更像面向对象的语义.
请看下面的代码:
function Car(sColor){
this.color = sColor;
}
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car("red");
oCar1.showColor();
现在看起来就更像创建一般对象了.这也是现在JS中最流行的创建对象的方式,有个规定,构造函数中规定属性值,方法一律在外面用原型的方式添加.
修改内置对象
在ECMAScript中,每个本地对象也有用法完全相同的prototype属性.比如,JS中,String类没有提供trim()方法,Java中此方法可以截取字符串两端的空格,那么我们怎么样在JS中创建此方法呢?
String.prototype.trim = function(){
return this.replace(/(^ +)|( +$)/g,"");
}
var str = " AAA ";
alert(str.length);
alert(str.trim().length);
创建自己的实用工具类
StringBuffer类,Java中是字符串缓冲类,具有较高的连接效率,我们在JS中怎么实现这个类呢.比如我们要执行一个字符串的连接操作,如果用+号进行连接,会造成生成许多临时字符串,这样非常消耗资源,会造成性能问题.最好的解决方法是用Array对象存储字符串,然后用join()方法(参数为空字符串"")创建最后的字符串.
function StringBuffer(){
this._strings_ = new Array();
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
}
StringBuffer.prototype.toString = function(){
this._strings_.join("");
}
var d1 = new Date();
var str = "";
for(var i=0; i<10000; i++ ){
str += "text";
}
var d2 = new Date();
document.write("连+所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
document.write("<BR><BR>");
var oBuffer = new StringBuffer();
d1 = new Date();
for(var i=0; i<10000; i++ ){
oBuffer.append("text");
}
d2 = new Date();
document.write("StringBuffer所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
经过测试,怪事发生了,竟然StringBuffer效率要低200%以上.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容介绍 项目结构: Controller层:使用Spring MVC来处理用户请求,负责将请求分发到相应的业务逻辑层,并将数据传递给视图层进行展示。Controller层通常包含控制器类,这些类通过注解如@Controller、@RequestMapping等标记,负责处理HTTP请求并返回响应。 Service层:Spring的核心部分,用于处理业务逻辑。Service层通过接口和实现类的方式,将业务逻辑与具体的实现细节分离。常见的注解有@Service和@Transactional,后者用于管理事务。 DAO层:使用MyBatis来实现数据持久化,DAO层与数据库直接交互,执行CRUD操作。MyBatis通过XML映射文件或注解的方式,将SQL语句与Java对象绑定,实现高效的数据访问。 Spring整合: Spring核心配置:包括Spring的IOC容器配置,管理Service和DAO层的Bean。配置文件通常包括applicationContext.xml或采用Java配置类。 事务管理:通过Spring的声明式事务管理,简化了事务的处理,确保数据一致性和完整性。 Spring MVC整合: 视图解析器:配置Spring MVC的视图解析器,将逻辑视图名解析为具体的JSP或其他类型的视图。 拦截器:通过配置Spring MVC的拦截器,处理请求的预处理和后处理,常用于权限验证、日志记录等功能。 MyBatis整合: 数据源配置:配置数据库连接池(如Druid或C3P0),确保应用可以高效地访问数据库。 SQL映射文件:使用MyBatis的XML文件或注解配置,将SQL语句与Java对象映射,支持复杂的查询、插入、更新和删除操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值