日期:2014-05-16  浏览次数:20390 次

JS架构探讨-精彩討論进行中...
    此前做过一个坦克大战小游戏,感谢大家热情回复,但从此中也发现前台开发人员水平参差,而且从接触到的同行可以看出,这方面大家的理解差距较大。

    JS前景很好,2014年HTML5标准更新之后,在很长的时间内,她都会越来越流行,特别是在游戏横行,移动设备更新快,很多人又不愿意用各种软件把手机弄得半死不活的今天,JS在移动设备上可能可能首先打败flash,成为前端的一哥。

    为什么要写此文?不可否认JS越来越流行,因为她灵活,什么样的水平都可以写出能实现功能的代码;这也突显出一个尖锐的问题:代码规范化。至于架构的重要性,我想不用多说,无非是规范代码、提高重用性、易扩展易维护。百度、新浪、豆瓣等都有自己的架构,今天在下分享一个DEMO,希望抛砖引玉,懂行的不要保留,分享是金;顺便把新浪架构PPT分享给大家。

    个人对架构的理解,无非是分层和模块化,以下代码主要基于此理解。使用jQuery作为底层,模块为中层,功能为上层、模块的组合。我们的目的是用此框架,我们可以把注意力集中在模块开发上,以实现易扩展、易重用、规范化的目标。

    待完善的地方有很多,比如针对每个页面独立一个配置文件(例如JSON),服务器端把此页面用到的JS合并压缩,以减少请求数,等,期待大家提出更多更好的建议。


核心实现:
constructor/js/aispeech.js
var AIS = (function() {
	var ONE_PROP = 'test'; // 私有属性和私有方法,只供框架内部使用
	return {
		create: function(obj, supr) { // 创建类或子类
			var sb = obj.initialize, sp;
			delete obj.initialize;
			if (!supr || typeof supr === 'object') {
				sb.prototype = obj;
			} else {
				sp = function() {};
				sp.prototype = supr.prototype;
				sb.prototype = new sp();
				sb.supr = sp.prototype;
				$.extend(sb.prototype, obj);
			}
			sb.prototype.constructor = sb;
			return sb;
		},
		getScript: function(url, cb) { // 引入js文件
			$.getScript(url, cb);
		},
		modual: {}, // 注册模块及其路径
		namespace: function(ns, cb) { // 命名空间
			var nsArr = ns.split('.'), o;
			o = window[nsArr[0]] = window[nsArr[0]] || {};
			$.each(nsArr.slice(1), function(i, n) {
				o = o[n] = o[n] || {};
			});
			AIS.modual[nsArr.slice(-1)].ns = ns;
			if (cb && typeof cb === 'function') cb.call(o);
		},
		importMD: function(modual, cb) { // 导入模块,根据模块名
			cb = cb || function() {};
			if (AIS.modual[modual].ns) {
				cb.call(eval(AIS.modual[modual].ns));
			} else {
				AIS.getScript(AIS.modual[modual].url, function() {
					cb.call(eval(AIS.modual[modual].ns));
				});
			}
		},
		util: { // 工具集
			isEmptyObject: function(obj) {
				for (var prop in obj) {
					return false;
				}
				return true;
			},
			toArray: function(arrLike) {
				return Array.prototype.slice(arrLike);
			},
			// browsers..
			isIE: function() {
				return !-[1,];
			}
		}
	}
})();

使用方法:
var A = AIS.create({
	initialize: function(name) { // 每个类都必须声明的构造器方法
		this.name = name;
	},
	hello: function() {
		alert('hello: '+ this.name);
	}
});
var a = new A('danny');
a.hello();
var B = AIS.create({  // B继承自A
	initialize: function(name, age) {
		B.supr.constructor.call(this, name);
		this.age = age;
	},
	world: function() {
		alert('world: '+ this.age);
	}
}, A);

一个用户登陆和切换用户的DEMO:
constructor/ais.modual.js
AIS.modual = {
	'login': {
		'url': 'js/login/login.js'
	},
	'switcher': {
		'url': 'js/login/switch.js'
	}
}

constructor/js/login/login.js
AIS.namespace('com.ais.aid201105.login', function() {
	//var PrivateClass = AIS.create({...}); 可以创建包内私有的类
	this.LoginForm = AIS.create({ // public class
		initialize: function(pid) {
			this.parentId = pid;
			this.initForm();
			this.submit();
		},
		initForm: function() {
			var $f = $('<form></form>');
			$f.append('<fieldset style="width: 250px;"></fieldset>').find('fieldset')
			.append('<legend>Login Form</legend>')
			.append('<label class="username">name: </label>&nbsp;<input type="text" id="username" /><br />')
			.append('<label class="password">password: </label>&nbsp;<input type="password" id="password" /><br />')
			.append('<label class="gender">gender: </label>&nbsp;<select id="gender"><option>male</option><option>female</option></select><br />')
			.append('<input type="button" id="submit" value="submit" />&nbsp;<input type="reset" va