面向对象
- 对象
- JS定义对象为“属性的无序集合”
- 基于代码的名词表示
- 类
- 每个对象都由类定义
- 实例
- 对象称为类的实例。
- 由类创建对象实例的过程叫做实例化(instantiation)
- ECMAScript中的类
- 没有类的概念
- 对象定义为对象的配方
- 大多数时候,所说的类等价于对象定义
- 面向对象语言的要求
- 封装
- 聚集:把一个对象存储在另一个对象内的能力
- 继承
- 多态
- 对象的构成
- JS中,对象由特性构成
- 特性为原始值或引用值
- 特性为函数,看作对象的方法
- 否则,看作对象的属性
对象的应用
- 对象的创建和销毁都在JS执行过程中发生
- 声明和实例化
new + ClassName
var oObject = new Object();
var oStringObject = new String();
- 对象引用
- 不能访问对象的物理表示
- 只能访问对象的引用
- 存储在对应变量中的,是对象的引用,而不是本身
- 对象废除
- JS有无用存储单元程序(garbage collection routinue)
- 当一个对象的引用没有是,该对象被废除。
- 运行GCR程序时,废除的对象都被销毁。
- 函数执行代码后,都会调用GCR
- 一些其他不可预知的清空下,也会调用GCR
- 把对象的所有引用设置为null时,可以强制废除对象
- 如果一个对象有多个引用,必须将所有引用都设置Null
- 早绑定和晚绑定
- 绑定(binding),把对象的接口与对象的实例结合在一起的方法
- 早绑定(early binding),指在实例化对象前,定义它的属性和方法。JS不支持早绑定.
- 晚绑定(late binding),在运行前,不知道对象的类型,运行时进行判断。JS所有变量都采用晚绑定。
ECMAScript对象类型
- 对象类型
- 本地对象
- 内置对象
- 宿主对象
- 本地对象
- 独立于宿主环境的JS实现提供的对象。
- 简单来说,本地对象是ECMA-262定义的类
Object
Function
Array
String
Boolean
Number
Date
RegExp
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
- 内置对象
- 为由ECMAScript实现提供,独立于宿主环境的所有对象
- ECMA-262定义了两个内置对象
Global
Math
- 宿主对象
- 所有非本地对象
- 由宿主环境提供的对象
- 如BOM和DOM
对象作用域
-
作用域:变量的使用范围
-
公有、私有、受保护
- JS只有公有作用域
- 如何私有?
- JS中并不能真正私有,只能假装私有
- obj.color = “blue” 表示该属性私有
- 静态作用域
- JS中没有静态作用域
- 关键字this
- JS中this指向调用该方法的对象
JS中定义类或对象
- 工厂方式
原始方式
var object = new Object();
o.name = "linduo";
o.age = "5";
o.show() = function() {
// ...
}
问题,无法便捷的创建多个实例
工厂方式
可以创建并返回特定类型的对象的工厂函数
function createPerson() {
var person = new Object();
person.name = "linduo";
person.age = "5";
person.show() = function() {
// ...
}
return person;
}
var p1 = new createPerson();
var p2 = new createPerson();
改进
在函数外定义对象的方法,使方法在内存中只有一份拷贝
function showColor() {
// ...
}
function createPerson(){
// ...
person.showColor = showColor;
return person ;
}
构造函数方式
- 构造函数
function person () {
this.xxx= xxx;
// ...
this.show() = function() {
// ...
}
}
** 问题:重复生成函数**
- 原型方式
function person () {
}
person .prototype.name= "linduo";
person .prototype.age = 5;
person .prototype.color = yellow;
person .prototype.showColor = function() {
alert(this.color);
};
var P1 = new person ();
var P2 = new person ();
问题:构造函数无参数,属性为引用类型时,属性被多个实例共享,修改一个,其他实例的该属性也改变
- 改进:构造函数+原型
- 构造函数定义对象的所有非函数属性
- 原型方式定义对象的函数属性
function person (name,age,color) {
this.name= name;
this.age= age;
this.color= color;
this.adress= new Array("CHN","SY");
}
person.prototype.showColor = function() {
alert(this.color);
};
JS开发时,采用的主要方式
- 动态原型方法
- 视觉上,更向面向对象语言
function person(name,age,color) {
this.name = name;
this.age = age;
this.color = color;
this.adress= new Array("CHN","SY");
if (typeof person._initialized == "undefined") {
person.prototype.showColor = function() {
alert(this.color);
};
person._initialized = true;
}
}
可以保证函数只存在一份
修改对象
- 创建新方法
可以使用原型为已有类添加新方法
Number.prototype.toHexString = function() {
return this.toString(16);
};
- 重命名已有方法,使用更易理解的函数名,封装相关动作的函数
- 覆盖原有方法,使用同名函数覆盖已有方法,原方法不可以在调用。可以使用以下方法,在覆盖前,保存原有方法。
// 通过originalToString()可以调用原有方法
Function.prototype.originalToString = Function.prototype.toString;
Function.prototype.toString = function() {
if (this.originalToString().length > 100) {
return "Function too long to display.";
} else {
return this.originalToString();
}
};
为本地对象添加新方法,在Object对象的prototype属性上定义。