给javascript加上 final 和 private 定义吧

前一段时间为了把backbone这个未完工的脚手架加工成一个全尺寸的框架,设计了一个叫做Stemcell的框架。但是javascript的灵活性,让框架的使用者在使用的过程中总会心惊胆颤,不知道什么时候会触碰了框架的底线(专业术语叫做G Spot),从而让系统处于“楼即将脆脆”的状态。 

于是在实现Stemcell的过程中愈加感觉其他面向类的语言(面向类的语言不是面向对象的语言)中的种种呆板的特性现在竟然有点天然呆的可爱,所以昨天下午花了3个小时实现了一个小的基于javascript对象的 对象模型: Class.Model.js

它定义了如下几个特性:

  • 一个BasicClass,认为所有从它派生出来的类都是继承自它
  • 一个extend方法,便于继承
  • 一个final字段的定义
  • 一个private字段的定义
快速进入主题在床上叫做“猴急”,在这篇文章的读者这叫做“对于知识的饥渴”,反正都是horny那点事。
下面就直接举个例子来说明:
定义类
比如我们按照Class.Model.js的规定定义了一个类Car:
var Car = Class.new({
	speed : null,
	color : null,
	initialize : function(args){
		this.speed = args.speed;
		this.color = args.color;
		this.distance = args.distance;
	},
	getHours : function(){
		
	}
})
 注: Class就是在Class.Model.js中定义的BasicClass. 它的类方法Class.new可以帮你定义一个新的类,接受的参数是新类的定义。
下面实例化这个类:
var car = Car.new({
	speed 		: "220KM",
	color		: "black",
	distance 	: "128320KM"
});
 这样将给对象car初始化属性如上。顺便说一下,定义的initialize方法会在构造函数执行结束之前最后进行执行。
 那么实例化后的car对象拥有三个属性: speed , color , distance
    however:
    distance属性没有在类定义中进行定义,见:
var Car = Class.new({
	speed : null,
	color : null,
	initialize : function(args){
		this.speed = args.speed;
		this.color = args.color;
		this.distance = args.distance;
	},
	getHours : function(){
	}
})
 
     属性定义中只有speed 和 color, 这不影响Car类自己实例的使用,但是Car的子类不会继承distance属性
  )
 还有两个方法: initialize , getHours 
定义私有方法
再来看看上边定义的Car这个类,如果要给他加上一个私有方法怎么做?
代码如下:
var Car = Class.new({
	speed : null,
	color : null,
	initialize : function(args){
		this.speed = args.speed;
		this.color = args.color;
		this.distance = args.distance;
	},
	getHours : function(){
		this.hours();
	}
	private : {
		hours : function(){
			var distance = parseInt(this.distance);
			var speed = parseInt(this.speed);
			var hours = distance / speed;
			alert("I have been driven for " + hours + " hours");
		}
	}
})
 
在类定义中添加一个字段private, 私有方法定义在private字段中。比如如上的类定义,在getHours方法中调用私有的hours方法,会弹出alert框告诉你这个车已经跑了多少个小时了。
但是如果:
var car = Car.new({
	speed 		: "220KM",
	color		: "black",
	distance 	: "128320KM"
});

car.hours(); // 会抛出一个“找不到方法”的错误
 如此,就定义了一个私有方法,不能在除car对象本身之外的作用域发起调用。
继承的定义
所有通过Class.new方法定义的类(或者是继承自Class.New定义的类的子类们)都有一个名为extend的类方法,可以让子类继承父类的属性和方法
代码如下:
var RaceCar = Car.extend({
	brand : null
});
 类RaceCar继承自Car类,所以RaceCar也继承了Car类的属性 : speed , color , 以及方法: initialize , getHours , 以及私有方法 hours (继承来的私有方法依然是子类的私有方法)
看上面的代码,可以发现,RaceCar类还新定义了一个属性 brand , 所以RaceCar类总共有三个属性speed , color , brand
除此之外,如果父类定义了任何类方法,那么子类同样会将这个类方法继承为自己的类方法。代码如下:
Car.find = function(){
	alert("looking for sth")
} 

// 为Car类定义了一个类方法 find

RaceCar.find() // -> 会弹出“looking for sth”
 

Car类有一个名为find的类方法,继承自Car的RaceCar 同样可以调用find方法。

final的定义

有时候我们希望框架的使用者在使用我们的框架时,不要因为继承而复写了我们父类中的方法,导致框架不可用,这时候非常需要javascript有类似final关键字,可以阻止这一惨剧的发生。

下面来看看Class.Model.js中final方法的定义,定义方法和private方法的定义类似,比如我们要给Car加上名为buzz的final方法,这个方法规定了车怎样鸣嘀,我们不希望不一样的车会有不同的鸣嘀方式,比如复写为“什么样的歌声才是最开怀”:

var Car = Class.new({
	speed : null,
	color : null,
	initialize : function(args){
		this.speed = args.speed;
		this.color = args.color;
		this.distance = args.distance;
	},
	getHours : function(){
		this.hours();
	},
	final : {
		buzz : function(){
			alert("i can speed up to " + this.speed + " , and I'm " + this.color);
		}
	},
	private : {
		hours : function(){
			var distance = parseInt(this.distance);
			var speed = parseInt(this.speed);
			var hours = distance / speed;
			alert("I have been driven for " + hours + " hours");
		}
	}
})
 

 将buzz方法的定义放在final字段中欧你,这样buzz方法就不能被子类复写了。

var RaceCar = Car.extend({
	brand : null
});
var car = Car.new({
	speed 		: "220KM",
	color		: "black",
	distance 	: "128320KM"
});
car.buzz() // --> 将会弹出框显示 “i can speed up to 220KM , and I'm black”
var raceCar = RaceCar.new({
	speed 	: "280KM",
	color	: "red",
	distance: "311983KM"
})
raceCar.buzz() // -> 会弹出类似的alert框

但是如果我们不小心在子类的定义中复写了buzz方法会怎么样呢?来看代码:

var RaceCar = Car.extend({
	brand : null,
        buzz : function(){
               alert("什么样的歌声才是最开怀!!!")
        }
});

 上面的RaceCar定义中重新定义了buzz方法,那么在js runtime运行到这个地方的时候会抛出一个异常:

  1. Uncaught Error: Overriding parent's final method ["buzz"] Class.Javascript.js:37
    1. checkOverrideClass.Javascript.js:37
    2. extendClass.Javascript.js:43
    3. (anonymous function)application.js:42

如此,就可以保证父类中的final字段下定义的方法不会被子类复写了。

Class.Model.js定义的对象模型就是这样的,只提供了几个简单的特性,如果对这个东西感兴趣,可以到

https://gist.github.com/4441106

找到Class.Model.js的代码。

欢迎fork欢迎使用欢迎提出意见北京欢迎您

相关推荐