代码重构(编写优雅的前端代码)
1.自执行函数,严格模式
将当前的模块对象写在一个自执行函数内。
需要使用ES5的严格模式。
该模块需要用到的全局变量需要用入参的方式传入自执行函数,供函数内部使用。
(function (global, $, doc, lsObj, zhugeSwitch, zhuge) {
'use strict';
/* 这里是代码 */
})(this, this.jQuery, document, lsObj, zhugeSwitch, zhuge);
2.构造函数与原型
为当前模块对象创建一个构造函数,和他的原型。
我们将构造函数作为模块的入口函数。入口函数里通常会执行初始化变量、绑定事件等等。
(function (global, $, doc, lsObj, zhugeSwitch, zhuge) {
'use strict';
var something = function(){
};
something.prototype = {
constructor: something,
}
})(this, this.jQuery, document, lsObj, zhugeSwitch, zhuge);
3.选择器统一管理
将选择器对象写在类属性中。
将初始化选择器的函数写在原型中,在构造函数内调用。
var something = function(){
this.initializeElements();
};
something.Eles = {
name: '.name',
password: '.password',
};
something.prototype = {
initializeElements: function () {
var eles = loginClass.Eles;
for (var name in eles) {
if (eles.hasOwnProperty(name)) {
this[name] = $(eles[name]);
}
}
}
}
4.事件统一管理
- ##### 将事件Map统一写在构造内。
var something = function(){
this.eventsMap = {
'focus .name input': 'nameFocus',
'blur .name input': 'nameBlur',
'focus .password input': 'pswdFocus',
'blur .password input': 'pswdBlur',
'click .btn': 'login',
};
};
- ##### 将事件要触发的函数写进原型中。
(注意此时this的指向)
something.prototype = {
login: function () {
var p = this.passwordInput;
var n = this.nameInput;
var pt = this.pTip;
var nt = this.nTip;
this.nameVal = n.val().trim();
this.passwordVal = MD5(p.val().trim());
var nameVal = this.nameVal;
var passwordVal = this.nameVal;
var phoneReg = /^1\d{10}$/;
if (nameVal == "" || nameVal == null) {
nt.text('手机号码不能为空');
p.val('')
} else if (!phoneReg.test(nameVal)) {
nt.text('您输入的手机号码不正确');
} else if (passwordVal == '' || passwordVal == null) {
nt.text('');
pt.text('密码不能为空');
} else {
nt.text('');
pt.text('');
this._requestIfTelregisted();
}
},
}
- ##### 我们会使用事件代理的方式对这些事件进行循环绑定。
在原型中书写一个扫描事件Map的函数。
something.prototype = {
_scanEventsMap: function (maps, isOn) {
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
var type = isOn ? 'on' : 'off';
for (var keys in maps) {
if (maps.hasOwnProperty(keys)) {
if (typeof maps[keys] === 'string') {
maps[keys] = this[maps[keys]].bind(this); //改变this的指向
}
var matchs = keys.match(delegateEventSplitter);
$('body')[type](matchs[1], matchs[2], maps[keys]);
}
}
},
}
- ##### 在原型中写入以下函数,优化我们的逻辑。
something.prototype = {
initialization: function () { //初始化
this.bindEvent();
},
bindEvent: function () { //绑定事件
this.initializeOrdinaryEvent(this.eventsMap);
},
unbindEvent: function () { //解绑事件
this.uninitializeOrdinaryEvent(this.eventsMap);
},
initializeOrdinaryEvent: function (maps) { //绑定普通事件
this._scanEventsMap(maps, true);
},
uninitializeOrdinaryEvent: function (maps) { //解绑普通事件
this._scanEventsMap(maps);
},
_scanEventsMap: function (maps, isOn) { //扫描事件地图,绑定或者解绑
},
}
- ##### 在构造函数内调用初始化函数。
var something = function(){
this.initialization();
};
5.添加属性和方法
当前模块对象会有一些初始化参数,可以理解为我们自己定义的全局变量。我们将这些参数写进构造函数中。
var something = function(){
this.passwordVal = null;
this.nameVal = null;
};
将其他用到的函数写入原型中。
something.prototype = {
_requestIfTelregisted: function () { // 验证手机号是否注册接口
var _data = {
"registNum": this.nameVal
};
var nt = this.nTip;
var that = this;
$.ajax({
type: "GET",
url: "/cloudlink-core-framework/login/isExist",
contentType: "application/json",
data: _data,
dataType: "json",
success: function (data, status) {
var res = data.rows.isExist;
if (res == 0) {
nt.text('账号未注册');
utils.zhugeTrackForFailed(that.nameVal,'账号未注册');
return false;
} else {
that._requestData();
return true;
}
}
});
},
}
6.抽离工具类(对象)
例如:
var utils = {
hide:function(ele){ //元素的显隐
$(ele).addClass('hidden');
},
show:function(ele){
$(ele).removeClass('hidden');
},
zhugeTrackForFailed: function (tel, sRsn) { //诸葛埋点
if (zhugeSwitch == 1) {
zhuge.track('登陆失败', {
'手机号': tel,
'原因': sRsn
});
}
},
};
7.执行构造函数
可以选择是否把类或new出的对象暴露出去。
//global.something = something; 选择是或否暴露
$(function() {
global.somethingObj = new something(); //暴露出对象,供其他使用
//new something(); 直接执行
});
8.最终结构
(function (global, $, doc, lsObj, zhugeSwitch, zhuge) {
'use strict';
var something = function(){
this.eventsMap = {
'focus .name input': 'nameFocus',
};
this.initializeElements();
this.initialization();
};
something.Eles = {
password: '.password',
};
var utils = {
zhugeTrackForFailed: function(tel, sRsn) {
if (zhugeSwitch == 1) {
zhuge.track('登陆失败', {
'手机号': tel,
'原因': sRsn
});
}
},
};
something.prototype = {
constructor: something,
initialization: function() {
this.bindEvent();
},
initializeElements: function() {
var eles = loginClass.Eles;
for (var name in eles) {
if (eles.hasOwnProperty(name)) {
this[name] = $(eles[name]);
}
}
},
bindEvent: function() {
this.initializeOrdinaryEvent(this.eventsMap);
},
unbindEvent: function() {
this.uninitializeOrdinaryEvent(this.eventsMap);
},
initializeOrdinaryEvent: function(maps) {
this._scanEventsMap(maps, true);
},
uninitializeOrdinaryEvent: function(maps) {
this._scanEventsMap(maps);
},
_scanEventsMap: function(maps, isOn) {
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
var type = isOn ? 'on' : 'off';
for (var keys in maps) {
if (maps.hasOwnProperty(keys)) {
if (typeof maps[keys] === 'string') {
maps[keys] = this[maps[keys]].bind(this);
}
var matchs = keys.match(delegateEventSplitter);
$('body')[type](matchs[1], matchs[2], maps[keys]);
}
}
},
destroy: function() {
this.unbindEvent();
}
}
//global.something = something; 选择是或否暴露
$(function() {
global.somethingObj = new something(); //暴露出对象,供其他使用
//new something(); 直接执行
});
})(this, this.jQuery, document, lsObj, zhugeSwitch, zhuge);