JavaScript基础强化笔记-对象
对象
object:属性的无序组合,每个属性存放一个原始值、对象或函数。
类
每个对象都由类定义,可以把类看做对象的配方。类不仅要定义对象的接口(interface),还要定义对象的内部工作。
编译器和解释程序都根据类的说明构件对象。
实例
程序使用类创建对象时,生成的对象叫做类的实例(instance)。
对类生成的对象的个数的唯一限制来自与运行代码的机器的物理内存。
ECMAScript 没有 正式的类
面向对象语言的要求
- 封装
- 聚集
- 继承
- 多态
对象的构成
- ECMAScript中,对象由特征(attribute)构成,特性可以是原始值,也可以是引用值。
- 如果特性存放的是函数,它将被看做为对象的方法。
- 否则该特性被看作对象的属性(property)
对象的应用
对象的创建和销毁都在JavaScript执行过程中发生,理解这种范式的含义对理解整个语言至关重要。
声明和实例化
var oObject = new Object()
var oStringObject = new String()
对象的创建方式是用关键字new后面跟上实例化的类的名字
如果构造函数无参数,可以省略括号
对象引用
在 ECMAScript 中,不能访问对象的物理表示,只能访问对象的引用。每次创建对象,存储在变量中的都是该对象的引用,而不是对象本身。
对象废除
ECMAScript 拥有无用存储单元收集程序(garbage collection routine),不必专门销毁对象来释放内存。
将对象的所有引用都设为null,可以强制性的废除对象
var oObject = new Object
oObject = null
对象的绑定
- 绑定(binding)即把对象的接口和对象实例结合在一起的方法。
- 早绑定(early binding)是指在实例化对象之前定义他的属性和方法。(ECMAScript不支持)
- 晚绑定(late binding)指的是编译器或解释器程序在运行前,不知道对象的类型。(ECMAScript 中的所有变量都采用晚绑定方法)
对象类型
- 在ECMAScript中,所有对象并非等同创建的。
- 一般来说,可以创建并使用的对象有三种:
- 本地对象
- 内置对象
- 宿主对象
本地对象
立于宿主环境的 ECMAScript 实现提供的对象
Object
Function
Array
String
Boolean
Number
Date
RegExp
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
内置对象
由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现
开发者不必明确实例化内置对象,它已被实例化了。
Global 对象
Math 对象
宿主对象
所有非本地对象都是宿主对象(host object)
由 ECMAScript 实现的宿主环境提供的对象
所有的BOM和DOM对象都是宿主对象。
对象的作用域
好像ES6已经改了 例如 let
、const
定义类或对象
使用预定义对象只是面向对象语言的能力的一部分,它真正强大之处在于能够创建自己专用的类和对象。
ECMAScript 拥有很多创建对象或类的方法。
工厂方式
function createCar(sColor,iDoors,iMpg) {
var oTempCar = new Object;
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = function() {
alert(this.color);
};
return oTempCar;
}
var oCar1 = createCar("red",4,23);
var oCar2 = createCar("blue",3,25);
oCar1.showColor(); //输出 "red"
oCar2.showColor(); //输出 "blue"
构造函数方式
就是通过一个同名函数来创建对象:
构造函数首字母大写,为了区别。
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function() {
alert(this.color);
};
}
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);
原型方式
该方式利用了对象的propotype属性。
可以把它看成创建新对象所依赖的原型。
- 首先用空的构造函数来设置类名。
- 然后所有的属性和方法都被直接赋予prototype属性。
function Car() {
}
Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car();
var oCar2 = new Car();
使用这种方式,还能用 instanceof 运算符检查给定变量指向的对象的类型。
缺点:
- 因为构造函数没有参数,所以不能通过传值的方式来初始化属性的值。
- 当属性指向的是对象是,改变一个实例的属性,所有实例的属性都会修改。
function Car() {
}
Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.drivers = new Array("Mike","John");
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car();
var oCar2 = new Car();
oCar1.drivers.push("Bill");
alert(oCar1.drivers); //输出 "Mike,John,Bill"
alert(oCar2.drivers); //输出 "Mike,John,Bill"
混合的构造函数/原型方式
联合使用构造函数和原型方式。
这种概念非常简单:
- 用构造函数定义对象的所有非函数属性
- 用原型方式定义对象的函数属性(方法)
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");
}
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);
oCar1.drivers.push("Bill");
alert(oCar1.drivers); //输出 "Mike,John,Bill"
alert(oCar2.drivers); //输出 "Mike,John"
动态原型方法
- 态原型方法的基本想法与混合的构造函数/原型方式相同。
- 即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。
- 唯一的区别是赋予对象方法的位置。
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");
if (typeof Car._initialized == "undefined") {
Car.prototype.showColor = function() {
alert(this.color);
};
Car._initialized = true;
}
}
混合工厂方式
- 这种方式通常是在不能应用前一种方式时的变通方法。
- 它的目的是创建假构造函数,只返回另一种对象的新实例。
function Car() {
var oTempCar = new Object;
oTempCar.color = "blue";
oTempCar.doors = 4;
oTempCar.mpg = 25;
oTempCar.showColor = function() {
alert(this.color);
};
return oTempCar;
}
var car = new Car();
目前使用最广泛的是混合的 构造函数/原型方式。此外,动态原始方法也很流行,在功能上与构造函数/原型方式等价。
修改对象
创建新方法
通过已有的方法创建新方法
用 prototype 属性为任何已有的类定义新方法
Number.prototype.toHexString = function() {
return this.toString(16);
};
var iNum = 15;
alert(iNum.toHexString()); //输出 "F"
重命名已有方法
还是通过原型
新定义一个enqueue方法来实现push方法
新定义一个dequeue方法来实现shift方法
Array.prototype.enqueue = function(vItem) {
this.push(vItem);
};
Array.prototype.dequeue = function() {
return this.shift();
};
添加与已有方法无关的方法
判断某个项在数组中的位置
Array.prototype.indexOf = function (vItem) {
for (var i=0; i<this.length; i++) {
if (vItem == this[i]) {
return i;
}
}
return -1;
}
为本地对象添加新方法
如果给每个本地对象添加新方法,必须在object对象的propotype属性上定义它。
Object.prototype.showValue = function () {
alert(this.valueOf());
};
var str = "hello";
var iNum = 25;
str.showValue(); //输出 "hello"
iNum.showValue(); //输出 "25"
重定义已有方法
只要将指针指向已有函数名就可以。
Function.prototype.toString = function() {
return "Function code hidden";
}
极晚绑定
不存在几万绑定,实现方法是对象实例化后再定义方法。
var o = new Object();
Object.prototype.sayHi = function () {
alert("hi");
};
o.sayHi();