首页 > 代码库 > JavaScript之OOP编程

JavaScript之OOP编程

定义一个对象的最简单的方法

var car = {
		color:"red",
		drive:function() {
			alert(this.color + " car moved");
		}
}
这个方法不是在非常有用,因为它创建了一个单独的对象,而这个对象和任何常见的数据结构没有任何联系,为了创建第二个car实例,必须重新定义它的结构.


通过构造函数创建一个新对象

function Car() {
	this.color = "red";
	this.drive = function(){
		alert(this.color + " car moved");
	}
}
var car = new Car();
car.drive();


JavaScript中的每个函数都有一个称为prototype的属性.如果某个函数被用作构造函数,则这个属性会被自动通过new调用创建对象的原型

function Car() {
	this.color = "red";
}

Car.prototype.drive = function(){
	alert(this.color + " car moved");
}

var car = new Car();
car.drive();

对prototype属性所做的任何更改能够应用于通过new Car()构造的每一个对象,不管它是在更改之前还是更改后创建.为Car.prototype 添加新函数.对于共享相同原型的每一个对象,该函数都可以立即使用,无论它是在更改之前或是之后构造,具体如下:

// 更新原型
function Car(color) {
	this.color = color;
}

Car.prototype.drive = function(){
	alert(this.color + " car is driving");
}

var car1 = new Car("red");
alert(car1.__proto__ === Car.prototype); // true
car1.drive();


// 为原型添加新的函数
Car.prototype.stop = function()	{
	alert(this.color + " car has stopped");
}

var car2 = new Car("blue");

// 共享同一对象原型的对象
alert(Object.getPrototypeOf(car1) === Object.getPrototypeOf(car2));  // true

// 这两个对象现在都能访问这个新的方法
car2.stop();
car1.stop();

面向对象的很重要一个特性就是继承了,这里只要介绍通过原型链继承

// 继承的基本设置
function Car(color) {
	this.color = color;
}

Car.prototype.drive = function(){
	alert(this.color + " car is driving");
}

Car.prototype.turn = function(direction) {
	alert(this.color + " car turns " + direction);
}

Car.prototype.stop = function() {
	alert(this.color + " car has stopped");
}

// 消防车
function FirTruck() {}

FirTruck.prototype.turnCannon = function(direction) {
	alert("Cannon moves to the " + direction);
}

var truck = new FirTruck();
// 因为Car.prototype 并不在truck对象的原型链中
// 因此方法move()并不可用
truck.move();
truck.turnCannon("right");

JavaScript中有一个很特殊的Object.create(proto, properties)方法, 注:IE8及以下不支持
它可以用来创建一个新的空白对象并将其原型设置为proto


function Car(color) {
	this.color = color;
}

Car.prototype.move = function(){
	alert(this.color + " car is driving");
}

Car.prototype.turn = function(direction) {
	alert(this.color + " car turns " + direction);
}

Car.prototype.stop = function() {
	alert(this.color + " car has stopped");
}
if(!Object.create){
        // 兼容性处理
        FireTruck.prototype = Car.prototype;
}else{
	FireTruck.prototype = Object.create(Car.prototype);
}

function FireTruck() {}

// 检查,以防万一
//alert(Object.getPrototypeOf(FireTruck.prototype) === Car.prototype);
// 如果为true
// 则Car.prototype被添加到链中

FireTruck.prototype.turnCannon = function(direction){
	alert("Cannon moves to the " + direction);
}

var truck = new FireTruck();
// 现在可以工作了,因为Car.prototype已经在truck对象的原型链中
truck.move();
truck.turnCannon("right");

代码可以运行,但其输出还是存在一些问题

true
undefined car is driving
Cannon moves to the right


小汽车的color现在可以通过Car的构造函数进行设置.构造函数本身没有执行,所以其color显示为undefined.这个问题很好解决,修改FireTruck构造函数,在其中添加对Car构造函数的调用,这样Car就可以初始化它自己的对象变量

function FireTruck() {
	Car.call(this, "red");
}
再次运行这段代码,欣赏一下正确的输出


即使该代码能够成功运行,但仍有一个小问题需要解决.当这个新函数创建时,它的prototype属性并不为空.它有一个称为constructor的属性将引用函数本身,当调用

    FireTruck.prototype = Object.create(Car.prototype);

时,该属性丢失,因为这个新建的对象并不具有自己的属性.可以将丢失的属性作为第二个参数传递给create


FireTruck.prototype = Object.create(Car.prototype, {
		constructor: {
			value: FireTruck,         // 和FireTruck.prototype.constructor一样
			enumerable: false,
			writable: true,
			configurable: true
		}
	});
这里的constructor并不是通常的属性.当对象的键值进行循环时,它不会出现,但可以通过名称直接访问.通过给create()的第二个参数传递属性"描述符"可以取得相同的效果
描述符具有如下所示的几个字段
    value: 初始值
    enumerable: 如果属性显示在对象属性的列表中, 在像for...in 这样的循环或Object.keys中
    writable: 如果属性可以被指派一个不同的值
    configurable: 如果描述符定义的规则可以被修改或其属性可以删除,则为true
这样就可以模仿真实的 constructor 的行为


 最终版本的的继承示例

function extend(subConstructor, superConstructor) {
	if(!Object.create){
		subConstructor.prototype = superConstructor.prototype;
		subConstructor.constructor = {
				value: FireTruck,         // 和FireTruck.prototype.constructor一样
				enumerable: false,
				writable: true,
				configurable: true
			}
	}else{
		subConstructor.prototype = Object.create(superConstructor.prototype, {
			constructor: {
				value: FireTruck,         // 和FireTruck.prototype.constructor一样
				enumerable: false,
				writable: true,
				configurable: true
			}
		});
	}
}

function Car(color) {
	this.color = color;
}

Car.prototype.move = function(){
	alert(this.color + " car is driving");
}

Car.prototype.turn = function(direction) {
	alert(this.color + " car turns " + direction);
}

Car.prototype.stop = function() {
	alert(this.color + " car has stopped");
}



function FireTruck() {
	Car.call(this, "red");
}

extend(FireTruck, Car);


FireTruck.prototype.turnCannon = function(direction){
	alert("Cannon moves to the " + direction);
}

var truck = new FireTruck();
truck.move();
truck.turnCannon("right");



JavaScript之OOP编程