JavaScript的"类"

  1. 基本创建“类”方式

var Class = function(){
	var klass = function(){
		this.init.apply(this, arguments);
	};
	klass.prototype.init = function(){};
	return klass;
};

var Person = new Class();
Person.prototype.init = function(){
	// 基于Person 的实例做初始化
};

Person.find = function(id){ /*...*/ };
Person.prototype.breath = function(){ /*...*/ };
Person.fn = Person.prototype;
Person.fn.run = function(){ /*...*/ };

// 用法
var person = new Person();
person.find(1);
person.breath();
person.run();

  2. 分辨类的静态属性和实例的属性

var Class = function() {
	var klass = function() {
		this.init.apply(this, arguments);
	};
	klass.prototype.init = function() {};
	//定义 prototype 的别名
	klass.fn = klass.prototype;
	// 定义类的别名
	klass.fn.parent = klass;
	// 给类添加属性
	klass.extend = function(obj) {
		var extended = obj.extended;
		for (var i in obj) {
			klass[i] = obj[i];
		}
		if (extended) extended(klass);
	};
	// 给实例添加属性
	klass.include = function(obj) {
		var included = obj.included;
		for (var i in obj) {
			klass.fn[i] = obj[i];
		}
		if (included) included(klass);
	};
	return klass;
};

var Person = new Class();
// 添加静态属性
Person.extend({
	find: function(id) { /* ... */ },
	exists: function(id) { /* ... */ }
});
//添加实例属性
Person.include({
	save: function(id) { /* ... */ },
	destroy: function(id) { /* ... */ }
});

var person = new Person();
person.save();  

   在类之间共享通用的属性

var ORMModule = {
	save: function(){
		// 共享的函数
	}
};
var Person = new Class();
var Asset = new Class();

Person.include(ORMModule);
Asset.include(ORMModule);

   JavaScript 是基于原型的编程语言,原型用来区别类和实例,这里提到一个概念:原型对象(prototypical object)。原型是一个“模板”对象,它上面的属性被用做初始化一个新对象。任何对象都可以作为另一个对象的原型对象,以此来共享属性。

  当读取一个对象的属性时,JavaScript 首先会在本地对象中查找这个属性,如果没有找到,JavaScript 开始在对象的原型中查找,若还未找到还会继续查找原型的原型,直到查找到Object.prototype。如果找到这个属性,则返回这个值,否则返回undefined。

  为了让子类继承父类的属性,首先需要定义一个构造函数。然后需要将父类的新实例赋值给构造函数的原型。

var Animal = function(){};
Animal.prototype.breath = function(){
	console.log('breath');
};

var Dog = function(){};

// Dog 继承了Animal
Dog.prototype = new Animal();
Dog.prototype.wag = function(){
	console.log('wag tail');
};

var dog = new Dog();
dog.wag();
dog.breath(); // 继承的属性

   3. 添加继承,通过传入一个可选的父类来创建新类

var Class = function(parent) {
	var klass = function() {
		this.init.apply(this, arguments);
	};

	// 改变klass 的原型  只有实例的属性才会被继承,而非类的属性
	if (parent) {
		var subclass = function() { };
		subclass.prototype = parent.prototype;
		klass.prototype = new subclass;
	};

	klass.prototype.init = function() {};
	//定义 prototype 的别名
	klass.fn = klass.prototype;
	// 定义类的别名
	klass.fn.parent = klass;
	klass._super = klass.__proto__;

	// 给类添加属性
	klass.extend = function(obj) {
		var extended = obj.extended;
		for (var i in obj) {
			klass[i] = obj[i];
		}
		if (extended) extended(klass);
	};
	// 给实例添加属性
	klass.include = function(obj) {
		var included = obj.included;
		for (var i in obj) {
			klass.fn[i] = obj[i];
		}
		if (included) included(klass);
	};
	return klass;
};

var Animal = new Class();
Animal.include({
	breath: function(){
		console.log('breath');
	}
});
var Cat = new Class(Animal);
var tommy = new Cat();
tommy.breath();  

   apply() 函数有两个参数:第1 个参数是上下文对象,第2 个参数是参数组成的数组。如果上下文对象是null,则使用全局对象代替。

   call() 函数的行为和apply() 函数类似,只是使用方法不一样。call() 的第1 个参数是上下文对象,后续是实际传入的参数序列。

functionName.apply(this, [1, 2, 3]);
functionName.call(this, 1, 2, 3);

   使用apply() 和call() 来更改上下文对象

//为了访问原始上下文对象,可以将this 的值存入一个局部变量中。
var clicky = {
	wasClicked: function(){ },
	addListeners: function(){
		var self = this;
		$('.clicky').click(function(){
			self.wasClicked();
		});
	}
};
clicky.addListeners();

//可以使用apply 来将这段代码变得更干净一些,通过将回调包装在另外一个匿名函数中,来保持原始的上下文
var proxy = function(func, thisObject){
	return function(){
		return func.apply(thisObject, arguments);
	};
};

var clicky = {
	wasClicked: function(){ },
	addListeners: function(){
		var self = this;
		$('.clicky').click(proxy(this.wasClicked, this));
	}
};
clicky.addListeners();

   4. 控制“类”的作用域 在类和实例中都添加proxy函数

var Class = function(parent){
	var klass = function(){
		this.init.apply(this,arguments);
	}
	//继承
	if (parent) {
		var subclass = function() { };
		subclass.prototype = parent.prototype;
		klass.prototype = new subclass();
	}
	
	klass.prototype.init = function(){};
	klass.fn = klass.prototype;
	klass.fn.parent = klass;
	klass._super = klass.__proto__;
	
	//类 静态属性
	klass.extend = function(obj){
		var extended = obj.extended;
		for(var i in obj){
			klass[i] = obj[i];
		}
		if(extended) extended(klass);
	}
	//类 实例属性
	klass.include = function(obj){
		var included = obj.included;
		for(var i in obj){
			klass.fn[i] = obj[i];
		}
		if(included) included(klass);
	}
	//类 作用域
	klass.proxy = function(func){
		var self = this;
		return(function(){
			return func.apply(self, arguments);
		});
	}
	klass.fn.proxy = klass.proxy;
	
	return klass;
}

var Button = new Class();
Button.include({
	init: function(element){
		this.element = jQuery(element);
		// 代理了这个click 函数
		this.element.click(this.proxy(this.click));
	},
	click: function(){ }
});

 

posted @ 2015-07-16 11:05  eyeear  阅读(288)  评论(0编辑  收藏  举报