如何搭建一个简单的、面向对象的javascript基础框架

如果以后公司再能让我独立做一套新的完整系统,那么我肯定会为这个系统再写一个前端框架,那么我到底该如何写这个框架呢?

在我以前的博客里我给大家展示了一个我自己写的框架,由于当时时间很紧张,做之前几乎没有完整的思考过我到底该如何去写这个框架,所以事后对于这个框架我有很多遗憾之处,当我重构过一次代码后我就没再做过任何重构操作的工作,因为我根本不想再去给它修修补补了,之所以有这个想法,就是我对我写的那个框架的基础架构不满意。

为什么不满意这个基础架构了?我们先来看看我当时封装框架的方式:

(function(window,document){
	var o1 ={},o2={};
	var outerObj = {
	o1:o1,
	o2:o2
}
	window.outerObj = outerObj;
})(window,document,undefined)

这段代码是我参考jQuery的编写方式,现在回头看看,这个编写方式无非就是用匿名函数把内部代码保护起来,除此之外真的没有用到什么javascript语言其他特性。不过当时这么写还是有我自己的考虑的,主要是从下面这三个角度思考:
要提高网站性能就得尽量减少页面加载时候的请求个数,因此外部的javascript文件越少越好;
单个请求的大小也要尽量最少,因此页面里javascript代码要尽量精简;
要向jQuery学习,在页面里编写的代码应该有固定的套路,只要是两个页面都会使用javascript代码都应该迁移到自己编写的javascript库里,其次,页面的javascript开发里容易出错的代码都应该由javascript库来完成

因此开发javascript库的时候将大量代码都迁移到一个外部文件里,这些代码有的是基础性的代码,例如一些工具类,grid的构建代码,遮罩功能等,还有些代码是业务代码例如:加密解密等,这些都集中在了一个外部文件,由于自己原框架的结构只是将这些代码通过匿名函数包装起来,而没有让基础性代码和业务代码解耦的方式,所以当时编写的javascript库就是一个大杂烩,很多东西交织在一起,这使得自己维护代码的时候不是很科学了,经常变成硬编码。

var opts = {
	version:"1.0.0",
	name:"sharpxiajun"
};
(function(opts){
	function Clazz(){
	return this.init(arguments);
}
Clazz.fn = Clazz.prototype = {
	init:function(opts){
		this.settings = opts;
		return this;
	},
	testInit:function(){
		// 直接打印对象
		console.log(this.settings);
		// 遍历对象输出
		for (var o in this.settings){
			console.log(this.settings[o]);
		}
		return this;
	}
}
	window.$ = new Clazz(opts)
	})(opts);
	// 测试
	$.testInit();

下面是我根据上面思考写的新的基础javascript基础框架模型,代码如下:

(function(window,document){
	function Clazz(){
		return this.init(arguments);
	}
	Clazz.fn = Clazz.prototype = {
		init:function(opts){
			this.settings = opts;
			return this;
		},
		testInit:function(){
			// 直接打印对象
			console.log(this.settings);
			// 遍历对象输出
			for (var o in this.settings){
				console.log(this.settings[o]);
			}
			return this;
		}
	};
	Clazz.addStaticMethod = function(nmSpace,obj,ftn){
		if (!Clazz[nmSpace]){Clazz[nmSpace] = {}}
		for (var i in obj){
			Clazz[nmSpace][i] = obj[i];
		}
		if (ftn) {ftn()}
	}
	Clazz.addObjectMethod = function(nmSpace,obj,ftn){
		if (!Clazz.fn[nmSpace]){Clazz.fn[nmSpace] = {}}
		for (var i in obj){
			Clazz.fn[nmSpace][i] = obj[i];
		}
		if (ftn) {ftn()}
	}
	window.Clazz = Clazz;
})(window,document,undefined)
var opts = {
	version:"1.0.0",
	name:"sharpxiajun"
};
Clazz.addStaticMethod("myStatic",{
	sClz:"static",
	staticFtn:function(){
	console.log(Clazz["myStatic"].sClz);
}
},function(){
	console.log("Add Static Method End!!!!!!!");
})
Clazz.addObjectMethod("myFirst",{
	sParam:"sharp",
	ftn01:function(s){
		this.sParam = s;
		return this;
	},
	ftn02:function(){
	console.log("sParam:" + this.sParam);
	return this;
}
},function(){
	console.log("Add Object Method End!!!!!!!");
})
var $ = new Clazz(opts);
// 测试一
$.testInit();
// 测试二
console.log($.myFirst.sParam);
$.myFirst.ftn01("My God!!!").ftn02();
// 测试三
console.log(Clazz.myStatic.sClz);
Clazz.myStatic.staticFtn();

这个代码里我在匿名函数里返回的是类(javascript里其实没有类的概念,但是有构造函数,所以javascript里的构造函数承担了类的作用,所以这里提javascript里的类应该是没问题的),而不是已经实例化好的对象。这样返回的东西既可以有静态的方法和属性又有属于对象的方法和属性了。

该结构里有一个Clazz.addStaticMethod方法,它的作用是给定义的类添加静态的方法,这个方法我设计了三个参数,第一个参数是个字符串,业务函数就是静态方法的作用域,看下面实例代码:

console.log(Clazz.myStatic.sClz);

  Clazz.myStatic.staticFtn();

这样就等于给静态变量一个保护,有人会问如果我们不传第一个参数怎么办?认真的童鞋注意,现在我给出的代码只是想表达我的想法,到了生产实现时候该方法会更加丰满点,那时如果用户不传作用域字段,那么添加的静态方法和属性就是直接属于类本身的。

第二个参数就是具体要添加的静态属性和静态方法,这里我用的是对象类型。

第三个参数是个回调函数,当静态方式添加成功后调用,当然用户也可以不传,加个回调函数参数,是我觉得在设计javascript方法时候都应该给一个回调函数,这就是在运用事件驱动编程的思想,这其实为自己留有余地,这么做常常会在你意想不到的时候发挥重要作用。

方法Clazz.addObjectMethod是给对象添加方法和属性的,这些方法和属性石赋予给原型对象的,参数类型和addStaticMethod相同,这里就不在累述了。

用户在使用addObjectMethod方法时候要注意this指针的运用,在每个要添加到对象的方法最后加上一个return this,这么做好处就是每个对象的返回值都是对象本身,这样我们就可以让我们的库拥有和jQuery一样的连缀写法,例如下面的代码:

console.log($.myFirst.sParam);

  $.myFirst.ftn01("My God!!!").ftn02();

在生产开发里,我们可以把公共的javascript代码直接写到库里,页面里的业务代码则直接通过扩展返回类的静态方法和属性以及对象方法和属性进行扩充。

上面这个结构基本达到我的需要了,如果我以后用javascriptMVC思想开发前端我估计这个基本结构已经够用,当然还要做些代码健壮性的处理,如果是传统前端页面开发估计还会有一定修改,传统网站的页面开发都是服务端和html混搭的,例如jsp,velocity文件,因此有很多重要数据都是服务端变量生成的,我们时常要把这些变量作为参数传给外部javascript文件,每个页面里的参数是不一样的,所以必须有个对象专门接收这个对象。这个好做,因此这里就不累述了。

上面这个结构使用了面向对象继承机制,原始库是父对象,而业务javascript文件则是子类了,不过这个子类是用命名空间来区分的。

不过有时候我们可能想冒险替换整个父对象的内容,这个需求在平时开发里并不常见,不过还是写了一个这样的方法,下面是改进的代码,具体如下:

(function(window,document){
	function Clazz(){
		return this._init(arguments);
	}
	Clazz.prototype = {
		_init:function(opts){
			this.settings = opts;
			return this;
		},
		testInit:function(){
			// 直接打印对象
			console.log(this.settings);
			// 遍历对象输出
			for (var o in this.settings){
				console.log(this.settings[o]);
			}
			return this;
		}
	};
	Clazz.addStaticMethod = function(nmSpace,obj,ftn){
		if (!Clazz[nmSpace]){Clazz[nmSpace] = {}}
		if (Object.prototype.toString.apply(obj) == "[object Object]"){
		for (var i in obj){
			Clazz[nmSpace][i] = obj[i];
		}
		window.Clazz = Clazz;
	}
	if (ftn) {ftn()}
	}
	Clazz.addObjectMethod = function(nmSpace,obj,ftn){
		if (!Clazz.prototype[nmSpace]){Clazz.prototype[nmSpace] = {}}
		if (Object.prototype.toString.apply(obj) == "[object Object]"){
			for (var i in obj){
				Clazz.prototype[nmSpace][i] = obj[i];
			}
			window.Clazz = Clazz;
		}
		if (ftn) {ftn()}
	}
	/*Clazz.newStaticMethod(){//todo..........}*/
	Clazz.newObjectMethod = function(obj,ftn){
		if (Object.prototype.toString.apply(obj) == "[object Object]"){
			var tmpInit = Clazz.prototype._init;
			Clazz.prototype = obj;
			Clazz.prototype._init = tmpInit;
			window.Clazz = Clazz;
		}
		if (ftn) {ftn()}
	}
	window.Clazz = Clazz;
})(window,document,undefined)
var opts = {
	version:"1.0.0",
	name:"sharpxiajun"
};
Clazz.addStaticMethod("myStatic",{
	sClz:"static",
	staticFtn:function(){
	console.log(Clazz["myStatic"].sClz);
}
},function(){
	console.log("Add Static Method End!!!!!!!");
})
Clazz.myStatic.staticFtn();
Clazz.newObjectMethod({
	newver:"1.0.3",
	testNewFtn:function(){
	console.log(this.newver);
	return this;
}
},function(){
	console.log("New Create Prototype Object End !!!!!!");
});
Clazz.addObjectMethod("myFirst",{
	sParam:"sharp",
	ftn01:function(s){
	this.sParam = s;
	return this;
},
ftn02:function(){
	console.log("sParam:" + this.sParam);
	return this;
}
},function(){
	console.log("Add Object Method End!!!!!!!");
})
var $ = new Clazz();
console.log("================================");
console.log($.newver);
$.testNewFtn().myFirst.ftn01("XXXX").ftn02();
console.log("================================");
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯学馆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值