`

第八章 自定义对象

    博客分类:
  • js
阅读更多
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.构造函数(推荐方式)

对象直接量

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 />");

设置属性法

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]构造函数


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 />");

属性的枚举

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);

属性的删除

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);

给对象添加方法

//先准备好方法,注意这里用到了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());

构造函数创建对象的缺点

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

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

原型方式

上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,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%以上.
分享到:
评论

相关推荐

    C++_面向对象程序设计_谭浩强 word完整版

    第1篇 基 本 知 识 ... 第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    C++ 面向对象程序设计

    总 目 录 ...第 8 章 类和对象 第 9 章 关于类和对象的进一步讨论 第 10 章 运算符重载 第 4 篇 面向对象的程序设计 第 11 章 继承与派生 第 12 章 多态性与虚函数 第 13 章 输入输出流 第 14 章 C++工具

    AuotCAD二次开发讲义

    第1章 AuotCAD开发概览 第2章 用户交互 第3章 AutoCAD数据库 第4章 实体对象 第5章 扩充数据 第6章 几何类 第7章 用户界面 第8章 自定义对象 第9章 反应器

    谭浩强_C++程序员设计_pdf(完整版)

    第1章 C++的初步知识 ...第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    C++程序设计谭浩强100%完整·清华大学

    第1篇 基 本 知 识 第1章 C++的初步知识 ...第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    C++程序设计PPT谭浩强电子教案

    第1章 C++的初步知识 ... 第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    C++程序设计(谭浩强完整版)

    第1篇 基 本 知 识 第1章 C++的初步知识 ...第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    谭浩强C++程序设计 pdf版

    谭浩强C++程序设计 pdf版,带目录,清华...第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    C++程序设计(谭浩强).pdf

    第 1篇 基 本 知 识 ...第 8章 类和对象 第 9章 关于类和对象的进一步讨论 第 10 章 运算符重载 第 4篇 面向对象 的程序设计 第 11 章 继承与派生 第 12 章 多态性与虚函数 第 13 章 输入出流 第 14 章 C++工具

    全国计算机二级c++复习课件

    全国计算机二级c++复习课件... 第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    大学C++课本,谭浩强版,电子教案。

    大学C++课本,谭浩强版... 第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具

    C++程序设计 谭浩强 PPT

    第8章 类和对象 第9章 关于类和对象的进一步讨论 第10章 运算符重载 第4篇 面向对象的程序设计 第11章 继承与派生 第12章 多态性与虚函数 第13章 输入输出流 第14章 C++工具 再次申明:这是PPT,不是书。

    -= Excel VBA实用技巧大全(848个实用技巧)=-

    第8章 利用对象事件运行程序 第9章 自定义菜单和自定义工具栏实用操作技巧 第10章 Excel数据清单实用操作技巧 第11章 工作簿作为数据库的实用操作技巧 第12章 Access数据库实用操作技巧  第13章 文本文件实用...

    C++程序设计_谭浩强.part2.rar

    作者:谭浩强 出版社:清华大学出版社 ...第八章 类和对象 第九章 关于类和对象的进一步讨论 第十章 运算符重载 第十一章 继承与派生 第十二章 多态性与虚函数 第十三章 输入输出流 第十四章 C++工具 附录A、B

    C++程序设计 谭浩强 电子版,文字版非扫描

    C++C++程序设计 ...第 8章 类和对象 第 9章 关于类和对象的进一步讨论 第 10 章 运算符重载 第 4篇 面向对象的程序设计 第 11 章 继承与派生 第 12 章 多态性与虚函数 第 13 章 输入出流 第 14 章 C++C++C++

    C++程序设计_谭浩强.part3.rar

    作者:谭浩强 出版社:清华大学出版社 ...第八章 类和对象 第九章 关于类和对象的进一步讨论 第十章 运算符重载 第十一章 继承与派生 第十二章 多态性与虚函数 第十三章 输入输出流 第十四章 C++工具 附录A、B

    C++程序设计_谭浩强.part1.rar

    作者:谭浩强 出版社:清华大学出版社 ...第八章 类和对象 第九章 关于类和对象的进一步讨论 第十章 运算符重载 第十一章 继承与派生 第十二章 多态性与虚函数 第十三章 输入输出流 第十四章 C++工具 附录A、B

    Visual C++2008程序设计完全自学教程

    第8章 自定义数据类型 第9章 对象和类 第10章 构造函数和类成员 第11章 类继承和友元关系  第12章 多态与虚拟函数 第13章 I/O与数据流处理 第14章 程序的调试 第15章 了解Windows Form的运作 第16章 公共...

    WPF编程宝典1-100

    第8章 元素绑定 第9章 命令 第10章 资源 第11章 样式和行为 第12章 形状、画刷和变换 第13章 几何图形和图画 第14章 效果和可视比对象 第15章 动画基础 第16章 高级动画 第17章 控件模板 第18章 自定义元素 第19章 ...

Global site tag (gtag.js) - Google Analytics