谈JavaScript代码封装
前言
也算老生常谈的问题了,再深入搞一搞怎么玩儿封装,如果看到这篇文章的你,正好你也是追求完美的代码洁癖狂者,那么这篇文章相信非常适合你。
举一个例子,编写一个Person类,具有name和birthday(时间戳)两个属性及对应的getter和setter方法,注意,setBirthday输入的参数是日期字符串,如"2016-04-08"。getBirthday同样得到的也是日期字符串。那么这个类是这样的——
var Person = function(name, birthday) {
this.name = name;
this.birthday = birthday; // timestamp
}; function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
} function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
} Person.prototype = {
setName: function(name) {
this.name = name;
},
getName: function() {
return this.name;
},
/**
* 设置生日
* @param dateString
*/
setBirthday: function(dateString) {
this.birthday = getTimestampOfInput(dateString);
},
/**
* 获取生日
* @returns {*}
*/
getBirthday: function() {
return getFormattedDay(this.birthday);
}
};
如果采用面向过程的方式去写,我们需要借助自执行匿名函数闭包的方式,如——
// 常用模式一:单例/静态 - 私有变量&共有方法
// 生成一个人
var person = (function() {
// 私有变量
var name = '';
var birthday = new Date().getTime(); // 默认是时间戳方式
// 共有方法
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
setBirthday: function(dateString) {
// 私有函数
function getTimestampOfInput() {
return new Date(dateString).getTime();
} birthday = getTimestampOfInput();
},
getBirthday: function() {
return getFormattedDay(birthday); // 函数式 - 不访问外界变量,没有闭包的呈现
// 有了输入,便有了预想中的输出,不保存状态
// 私有函数 - 已工具方法存在
function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
}
}
};
})(); person.setName('king');
console.log(person.getName()); person.setBirthday('2016-4-8');
console.log(person.getBirthday());
一、精分面向过程的写法
要知道,上面的面向过程person是一个单例,这种写法更像是一种命名空间提供工具函数的方式,如——
/**
* @file cookie
* @author
*/
define(function (require, exports, module) { /**
* 操作 cookie
*
* 对外暴露三个方法:
*
* get()
* set()
* remove()
*
* 使用 cookie 必须了解的知识:
*
* 一枚 cookie 有如下属性:
*
* key value domain path expires secure
*
* domain: 浏览器只向指定域的服务器发送 cookie,默认是产生 Set-Cookie 响应的服务器的主机名
* path: 为特定页面指定 cookie,默认是产生 Set-Cookie 响应的 URL 的路径
* expires: 日期格式为(Weekday, DD-MON-YY HH:MM:SS GMT)唯一合法的时区是 GMT,默认是会话结束时过期
* secure: 使用 ssl 安全连接时才会发送 cookie
*
* 有点类似命名空间的意思
*
*/ 'use strict'; /**
* 一小时的毫秒数
*
* @inner
* @const
* @type {number}
*/
var HOUR_TIME = 60 * 60 * 1000; /**
* 把 cookie 字符串解析成对象
*
* @inner
* @param {string} cookieStr 格式为 key1=value1;key2=value2;
* @return {Object}
*/
function parse(cookieStr) { if (cookieStr.indexOf('"') === 0) {
// 如果 cookie 按照 RFC2068 规范进行了转义,要转成原始格式
cookieStr = cookieStr.slice(1, -1)
.replace(/\\"/g, '"')
.replace(/\\\\/g, '\\');
} var result = { }; try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
cookieStr = decodeURIComponent(cookieStr.replace(/\+/g, ' ')); $.each(
cookieStr.split(';'),
function (index, part) {
var pair = part.split('=');
var key = $.trim(pair[0]);
var value = $.trim(pair[1]); if (key) {
result[key] = value;
}
}
);
}
catch (e) { } return result;
} /**
* 设置一枚 cookie
*
* @param {string} key
* @param {string} value
* @param {Object} options
*/
function setCookie(key, value, options) { var expires = options.expires; if ($.isNumeric(expires)) {
var hours = expires;
expires = new Date();
expires.setTime(expires.getTime() + hours * HOUR_TIME);
} document.cookie = [
encodeURIComponent(key), '=', encodeURIComponent(value),
expires ? ';expires=' + expires.toUTCString() : '',
options.path ? ';path=' + options.path : '',
options.domain ? ';domain=' + options.domain : '',
options.secure ? ';secure' : ''
].join('');
} /**
* 读取 cookie 的键值
*
* 如果不传 key,则返回完整的 cookie 键值对象
*
* @param {string=} key
* @return {string|Object|undefined}
*/
exports.get = function (key) {
var result = parse(document.cookie);
return $.type(key) === 'string' ? result[key] : result;
}; /**
* 写入 cookie
*
* @param {string|Object} key 如果 key 是 string,则必须传 value
* 如果 key 是 Object,可批量写入
* @param {*=} value
* @param {Object=} options
* @property {number=} options.expires 过期小时数,如 1 表示 1 小时后过期
* @property {string=} options.path 路径,默认是 /
* @property {string=} options.domain 域名
* @property {boolean=} options.secure 是否加密传输
*/
exports.set = function (key, value, options) { if ($.isPlainObject(key)) {
options = value;
value = null;
} options = $.extend({ }, exports.defaultOptions, options); if (value === null) {
$.each(
key,
function (key, value) {
setCookie(key, value, options);
}
);
}
else {
setCookie(key, value, options);
}
}; /**
* 删除某个 cookie
*
* @param {string} key
* @param {Object=} options
* @property {string=} options.path cookie 的路径
* @property {string=} options.domain 域名
* @property {boolean=} options.secure 是否加密传输
*/
exports.remove = function (key, options) { if (key == null) {
return;
} options = options || { };
options.expires = -1; setCookie(
key,
'',
$.extend({ }, exports.defaultOptions, options)
);
}; /**
* 默认属性,暴露给外部修改
*
* @type {Object}
*/
exports.defaultOptions = {
path: '/'
}; });
对于这个person单例或者理解为一个普通的(命名空间)对象,我们会发现两个工具函数(用于birthday的格式化)——
getTimestampOfInput:服务于setBirthday这个方法
getFormattedDay:服务于getBirthday这个方法
1.1 将工具函数私有性封装,利用闭包缓存该工具函数
会发现,每一次执行setBirthday,都会创建getTimestampOfInput这个函数,执行完setBirthday之后,getTimestampOfInput又会被销毁;同理getFormattedDay方法。私有性,我们做到了,但是每一次都需要去创建工具函数(getTimestampOfInput和getFormattedDay)。如果我们想把工具函数仅仅执行一次,可以这样写——
// 常用模式一:单例/静态 - 私有变量&共有方法
// 生成一个人
var person = (function() {
// 私有变量
var name = '';
var birthday = new Date().getTime(); // 默认是时间戳方式
// 共有方法
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
setBirthday: (function() {
// 私有函数
function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
}
return function(dateString) {
getTimestampOfInput(dateString);
};
})(),
getBirthday: (function() {
// 函数式 - 不访问外界变量,没有闭包的呈现
// 有了输入,便有了预想中的输出,不保存状态
// 私有函数 - 已工具方法存在
function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
}
return function() {
return getFormattedDay(birthday);
};
})()
};
})();
要看见里面用了一层闭包哦,也就是多需要耗损内存,但换来了性能上的优化。
1.2 将工具函数抽取为私有
我们继续变态的走下去,把这两个工具函数抽取出来,如——
// 常用模式一:单例/静态 - 私有变量&共有方法
// 生成一个人
var person = (function() {
// 私有变量
var name = '';
var birthday = new Date().getTime(); // 默认是时间戳方式
// 函数式 - 不访问外界变量,没有闭包的呈现
// 有了输入,便有了预想中的输出,不保存状态
// 私有函数 - 已工具方法存在
function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
}
// 函数式 - 不访问外界变量,没有闭包的呈现
// 有了输入,便有了预想中的输出,不保存状态
// 私有函数 - 已工具方法存在
function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
}
// 共有方法
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
setBirthday: function(dateString) {
birthday = getTimestampOfInput(dateString);
},
getBirthday: function() {
return getFormattedDay(birthday);
}
};
})();
那么这两个工具方法同样具有私有性,但是它能够服务的方法就更多了,所有对外暴露的方法(如将来有个新的方法getCreateDay),都可以使用这两个工具函数。
1.3 将工具函数显示声明为私有
OK,我们看到上面的例子中,name,birthday,包含两个工具方法都是私有的,我们可以使用"_"的方式来显示声明它是私有的,就可以这样去改装——
// 常用模式一:静态私有变量&共有方法
// 生成一个人
var person = {
// 单例的私有属性 - 或者可理解为静态变量
_name: '',
// 单例的私有属性 - 或者可理解为静态变量
_birthday: new Date().getTime(), // 默认是时间戳方式
// 工具函数
_getTimestampOfInput: function(dateString) {
return new Date(dateString).getTime();
},
// 工具函数
_getFormattedDay: function(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
},
// 共有方法
setName: function(newName) {
this._name = newName;
},
getName: function() {
return this._name;
},
setBirthday: function(dateString) {
this._birthday = this._getTimestampOfInput(dateString);
},
getBirthday: function() {
return this._getFormattedDay(this._birthday);
}
};
看起来还不错,但是私有属性还是可以被访问的,如person._birthday,
1.4 利用private和public命名空间来实现私有和共有
那么,我们想要让私有的属性达到真正的私有,并借助命名空间的方式,会有这个方式——
// 常用模式一:静态私有变量&共有方法
// 生成一个人
var person = (function() {
// 该对象保存静态属性
// 保存单例的状态
var _private = {
// 单例的私有属性 - 或者可理解为静态变量
_name: '',
// 单例的私有属性 - 或者可理解为静态变量
_birthday: new Date().getTime(), // 默认是时间戳方式
// 工具函数
getTimestampOfInput: function(dateString) {
return new Date(dateString).getTime();
},
// 工具函数
_getFormattedDay: function(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
},
getFormattedDayOfBirthday: function() {
return this._getFormattedDay(this._birthday);
}
}; // 共有对象
var _public = {
setName: function(newName) {
_private._name = newName;
},
// 直接从_private对象中获取
getName: function() {
return _private._name;
},
/**
* 可直接操作_private中的静态属性
* @param dateString
*/
setBirthday: function(dateString) {
_private._birthday = _private.getTimestampOfInput(dateString);
},
getBirthday: function() {
return _private.getFormattedDayOfBirthday();
}
}; return _public;
})();
_private和_public这两个命名空间还不错。在此基础上,建议把工具函数拿出来,可以这样——
// 常用模式一:静态私有变量&共有方法
// 生成一个人
var person = (function() { // 工具函数
// 可供_private和_public对象共用
function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
}
// 工具函数
// 可供_private和_public对象共用
function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
} // 该对象保存静态属性
// 保存单例的状态
var _private = {
// 单例的私有属性 - 或者可理解为静态变量
_name: '',
// 单例的私有属性 - 或者可理解为静态变量
_birthday: new Date().getTime() // 默认是时间戳方式
}; // 共有对象
var _public = {
setName: function(newName) {
_private._name = newName;
},
// 直接从_private对象中获取
getName: function() {
return _private._name;
},
/**
* 可直接操作_private中的静态属性
* @param dateString
*/
setBirthday: function(dateString) {
_private._birthday = getTimestampOfInput(dateString);
},
getBirthday: function() {
return getFormattedDay(_private._birthday);
}
}; return _public;
})();
1.5 将工具函数就近于它的调用者
有些同学非常喜欢将工具函数靠近与它的调用者,类似于这样——
// 常用模式一:静态私有变量&共有方法
// 生成一个人
var person = (function() { // 该对象保存静态属性
// 保存单例的状态
var _private = {
// 单例的私有属性 - 或者可理解为静态变量
_name: '',
// 单例的私有属性 - 或者可理解为静态变量
_birthday: new Date().getTime() // 默认是时间戳方式
}; _private.name = '';
_private.birthday = new Date().getTime(); // 默认是时间戳方式 var _public = {}; _public.setName = function(newName) {
_private._name = newName;
}; _public.getName = function() {
return _private._name;
}; // 工具函数
// 可供_private和_public对象共用
function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
}
_public.setBirthday = function(dateString) {
_private._birthday = getTimestampOfInput(dateString);
}; // 工具函数
// 可供_private和_public对象共用
function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
}
_public.getBirthday = function() {
return getFormattedDay(_private._birthday);
}; return _public;
})();
1.6 将工具函数放入util等全局命名空间
同样的,我们发现这两个工具函数具有通用性,可以放置于全局,供所有函数使用,那么就有这样的方式,如——
// 这里的工具类,可以以单独文件存在,供全局工程来使用
var util = {
/**
* 生日格式化显示
* @param timestamp
* @returns {string}
* @private
*/
getFormattedDay: function(timestamp) { // 模拟实现静态方法
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
},
/**
* 根据用户输入来获取时间戳,如输入'1995-10-05'
* @param timestamp
* @returns {string}
* @private
*/
getTimestampOfInput: function(dateString) {
return new Date(dateString).getTime();
}
}; var person = (function() {
// 私有变量
var name = '';
var birthday = new Date().getTime(); // 默认是时间戳方式
// 共有方法
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
setBirthday: function(dateString) {
birthday = util.getTimestampOfInput(dateString);
},
getBirthday: function() {
return util.getFormattedDay(birthday);
}
};
})();
上面这种方式,也是我们最常用的方式,很直观,易维护。
OK,那么面向过程的写法方式,就算是精分完了,很变态对不对?
总之,没有严格的对错,按照你认同喜欢的模式来。下面精分一下面向对象的写法。
二、精分面向对象的写法
面向对象的写法,要注意prototype中的方法供所有实例对象所共有,且这里的方法都是对实例状态变更的说明,即对实例属性的操作的变更。
2.1 不要把工具函数放入prototype中
基于前言里面的例子,我们常常不注意的将工具函数也都放在prototype当中,如——
// 多实例
var Person = function(name, birthday) {
this.name = name;
this.birthday = birthday; // timestamp
};
Person.prototype = {
setName: function(name) {
this.name = name;
},
getName: function() {
return this.name;
},
/**
* 设置生日
* @param dateString
*/
setBirthday: function(dateString) {
this.birthday = this._getTimestampOfInput(dateString);
},
// 工具函数
_getTimestampOfInput: function(dateString) {
return new Date(dateString).getTime();
},
/**
* 获取生日
* @returns {*}
*/
getBirthday: function() {
return this._getFormattedDay(this.birthday);
},
// 工具函数
_getFormattedDay: function(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
}
};
会看见上面的_getTimestampOfInput和_getFormattedDay两个方法也都放置在了prototype当中,然而这里的方法并没有操作实例属性,因此不应该将这类工具方法置于prototype当中。
2.2 不要将缓存变量放入this当中
还有一个大家常常犯的一个大错误,就是习惯性把各个方法间通讯的变量放入到this当中,如下——
var Person = function(name, birthday) {
this.name = name;
this.birthday = birthday; // timestamp
}; function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
} function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
} Person.prototype = {
setName: function(name) {
this.name = name;
},
getName: function() {
return this.name;
},
/**
* 设置生日
* @param dateString
*/
setBirthday: function(dateString) {
this.birthday = getTimestampOfInput(dateString);
},
/**
* 获取生日
* @returns {*}
*/
getBirthday: function() {
// 不要把缓存变量放置于this中
this.birthdayOfFormatted = getFormattedDay(this.birthday);
return this.birthdayOfFormatted;
}
};
会看到,这里的this.birthdayOfFormatted是一个缓存变量,并不能代表这个实例的某个状态。好了,我们回到正确的方式。
2.3 将工具函数就近于方法的调用者
// 多实例 - 抽取工具函数
var Person = function(name, birthday) {
this.name = name;
this.birthday = birthday; // timestamp
}; Person.prototype.setName = function(name) {
this.name = name;
}; Person.prototype.getName = function() {
return this.name;
}; // 工具函数
function getTimestampOfInput(dateString) {
return new Date(dateString).getTime();
} Person.prototype.setBirthday = function(dateString) {
this.birthday = getTimestampOfInput(dateString);
}; // 工具函数
function getFormattedDay(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
} Person.prototype.getBirthday = function() {
return getFormattedDay(this.birthday);
};
在维护性方面略胜一筹,主要看个人的变成习惯。
2.4 将工具函数放入类命名空间中,充当类的静态函数
// 多实例 - 抽取工具函数
var Person = function(name, birthday) {
this.name = name;
this.birthday = birthday; // timestamp
}; // 工具函数 - 对外静态变量
Person.getTimestampOfInput = function (dateString) {
return new Date(dateString).getTime();
}; // 工具函数 - 对外静态变量
Person.getFormattedDay = function(timestamp) {
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
}; Person.prototype = {
setName: function(name) {
this.name = name;
},
getName: function() {
return this.name;
},
/**
* 设置生日
* @param dateString
*/
setBirthday: function(dateString) {
this.birthday = Person.getTimestampOfInput(dateString);
},
/**
* 获取生日
* @returns {*}
*/
getBirthday: function() {
return Person.getFormattedDay(this.birthday);
}
};
我个人比较推荐这种写法,当然也可以把工具函数放入某个类似于util的命名空间中,供全局调用。
2.5 将工具函数放入util等全局命名空间
// 这里的工具类,可以以单独文件存在,供全局工程来使用
var util = {
/**
* 生日格式化显示
* @param timestamp
* @returns {string}
* @private
*/
getFormattedDay: function(timestamp) { // 模拟实现静态方法
var datetime = new Date(timestamp);
var year = datetime.getFullYear();
var month = datetime.getMonth() + 1;
var date = datetime.getDate();
return year + '-' + (String(month).length < 2 ? "0" + month : month) + "-"
+ (String(date).length < 2 ? "0" + date : date);
},
/**
* 根据用户输入来获取时间戳,如输入'1995-10-05'
* @param timestamp
* @returns {string}
* @private
*/
getTimestampOfInput: function(dateString) {
return new Date(dateString).getTime();
}
}; // 多实例 - 抽取工具函数
var Person = function(name, birthday) {
this.name = name;
this.birthday = birthday; // timestamp
}; Person.prototype = {
setName: function(name) {
this.name = name;
},
getName: function() {
return this.name;
},
/**
* 设置生日
* @param dateString
*/
setBirthday: function(dateString) {
this.birthday = util.getTimestampOfInput(dateString);
},
/**
* 获取生日
* @returns {*}
*/
getBirthday: function() {
return util.getFormattedDay(this.birthday);
}
};
好啦,整个面向对象的写法方式介绍到这儿。
总之,归于一点——要知道什么方法可以当做工具函数处理,并合理地放置工具函数的位置。
三、总结
整篇文章主要围绕工具函数的写法展开,模式不同,没有对与错,依照自身的编码习惯而定。欢迎看到文章的博友补充。
谈JavaScript代码封装的更多相关文章
- 浅谈JavaScript代码性能优化
可以通过https://jsbench.me/测试网站完成性能测试. 一.慎用全局变量 1.全局变量定义在全局执行上下文,是所有作用域链的顶端,在局部作用域中没找到的变量都会到全局变量中去查找,所以说 ...
- 浅谈JavaScript代码性能优化2
一.减少判断层级 从下图代码中可以明显看出,同样的效果判断层级的减少可以优化性能 二.减少作用域链查找层级 简单解释下,下图中第一个运行foo函数,bar函数内打印name,bar作用域内没有name ...
- 2016/11/17 周四 <javascript的封装简单示例>
这是一个简单的javascript代码封装的示例以及封装后的调用方法: var ticker={ n:0, add:function() { this.n++; }, show:function() ...
- 浅谈javascript函数节流
浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...
- 引爆你的Javascript代码进化
转自:http://www.hicss.net/evolve-your-javascript-code/ 方才在程序里看到一段JS代码,写法极为高明,私心想着若是其按照规范来写,定可培养对这门语言的理 ...
- 引爆你的Javascript代码进化 (转)
转自 海玉的博客 方才在程序里看到一段JS代码,写法极为高明,私心想着若是其按照规范来写,定可培养对这门语言的理解,对JS编程能力提高必是极好的.说人话:丫代码写的太乱,看的窝火! 最近闲暇无事,准备 ...
- 【Web技术】399- 浅谈前端代码加密
作者简介:于航,PayPal Senior Software Engineer,在 PayPal 上海负责 Global GRT 平台相关的技术研发工作.曾任职于阿里巴巴.Tapatalk 等企业.f ...
- 浅谈:javascript的面向对象编程之具体实现
下面的javascript代码都是需要使用jQuery插件来做的.希望大家可以搭建好工作环境 首先我们来做一个练习:在一个删除的超链接中添加一个提示信息,提示是否确认删除. 一般情况下我们都会这么做 ...
- 如何让你的JavaScript代码更加语义化
语义化这个词在 HTML 中用的比较多,即根据内容的结构化选择合适的标签.其作用不容小觑: 赋予标签含义,让代码结构更加清晰,虽然我们可以在标签上添加 class 来标识,但这种通过属性来表示本体的形 ...
随机推荐
- ORACLE RAC集群的体系结构
RAC是一个完整的集群应用环境,它不仅实现了集群的功能,而且提供了运行在集群之上的应用程序,即Oracle数据库.无论与普通的集群相比,还是与普通的Oracle数据库相比,RAC都有一些独特之处. R ...
- HD2157How many wasy??(十大矩阵问题之八 + 邻接矩阵的应用)
How many ways?? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- ci创建zip
public function createZip() { $this->load->library("zip"); $name = "test.text&q ...
- Cannot find class [org.apache.commons.dbcp.BasicDataSource]
错误:Cannot find class [org.apache.commons.dbcp.BasicDataSource] 原因:缺少commons-dbcp.jar
- iOS-解决iOS8及以上设置applicationIconBadgeNumber报错的问题
在IOS7中设置applicationIconBadgeNumber不会有什么问题,但是直接在IOS8中设置applicationIconBadgeNumber会报错.因为在IOS8中要想设置appl ...
- Array和ArrayList互相转换
class Order{ public string orderId; public string orderName; public decimal orderPrice; } public cla ...
- RHEL 安装gcc 艰难历程
装好系统后···· 各种搜的方案都不好使····· 最后搜到有人说在刚装系统的时候定制软件之类的那个地方选上“开发工具”就可以...
- 【初级为题,大神绕道】The app icon set named "AppIcon" did not have any applicable content 错误#解决方案#
The app icon set named "AppIcon" did not have any applicable content 错误,怎样解决 按照您的错误提示您应该 ...
- iOS开发之#iPhone6与iPhone6Plus适配#Xcode6.0/Xcode6.1上传应用过程中一些变动以及#解决方案#
更新时间2014年11月13日 本博文创建时,只有Xcode6.0, Xcode6.0尝试多次,确实如此 之后在6.1版本经博主少量尝试,确实也有如下问题,现更新下博客! iOS8发布之后,苹果强制 ...
- Drainage Ditches(dinic)
Drainage Ditches Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 59210 Accepted: 2273 ...