-
-
可用js-cookie替代
-
可用
URL、URLSearchParams替代 -
可用js原生替代
// 时间戳 -> yyyy.MM.dd
export function formatTimestamp(timestamp: number | string): string {
const date = new Date(timestamp);
const month = date.getMonth() + 1;
const day = date.getDate();
return `${date.getFullYear()}.${month >= 10 ? month : `0${month}`}.${day >= 10 ? day : `0${day}`}`;
}
/* 使用测试 */
formatTimestamp(new Date("2020/09/09").getTime())var format = {
date: function (dateObj, fmt) { /* 格式化日期 */
var o = {
'q+': Math.floor((dateObj.getMonth() + 3) / 3), // 季度
'M+': dateObj.getMonth() + 1, // 月
'd+': dateObj.getDate(), // 日
'h+': dateObj.getHours() % 12 === 0 ? 12 : dateObj.getHours() % 12, // 12小时制
'H+': dateObj.getHours(), // 24小时制
'm+': dateObj.getMinutes(), // 分
's+': dateObj.getSeconds(), // 秒
'S': dateObj.getMilliseconds(), // 毫秒
},
week = {
'0': '日',
'1': '一',
'2': '二',
'3': '三',
'4': '四',
'5': '五',
'6': '六',
},
i;
/* [{y:'7'},{yy:'17'},{yyy+:'017'},{yyyy+:'2017'}] */
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (dateObj.getFullYear() + '').substring(4 - RegExp.$1.length));
}
/* [{E:'一'},{EE:'周一'},{EEE+:'星期一'}] */
if (/(E+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '星期' : '周') : '') + week[dateObj.getDay() + '']);
}
for (i in o) {
if (new RegExp('(' + i + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[i]) : (('00' + o[i]).substr(('' + o[i]).length)));
}
}
return fmt;
},
};
/* 使用测试 */
var a = format.date(new Date(), 'yyyy-MM-dd HH:mm:ss S毫秒 EEE 季度q');/**
* 获取年龄
* @param {String|Number} birthday - 年月日(8位,如:'19900220'或19900220) 或 空字符串
* @returns {String} age - 年龄 或 空字符串
*/
function getAge (birthday) {
birthday = birthday.toString()
var age = 0
if (birthday && birthday.length === 8) {
var now = new Date()
var nowYear = now.getFullYear()
var nowMonth = now.getMonth() + 1
var nowDay = now.getDate()
if (nowMonth < 10) {
nowMonth = '0' + nowMonth
}
if (nowDay < 10) {
nowDay = '0' + nowDay
}
age = Math.floor((parseInt('' + nowYear + nowMonth + nowDay, 10) - parseInt(birthday, 10)) / 10000)
}
if (age > 0) {
age = age.toString()
} else {
age = ''
}
return age
}-
统一输出
/** * 显示倒计时,统一输出 * @constructor * @param {Object} data * @param {Number} data.deadline - 到期的时间戳 * @param {Object} [data.dom] - 输出节点,若不是节点则console.log输出 * @param {Function} [data.callback] - 到点后的回调函数 * @param {Number} [data.leftSec = 0] - 提前到期的秒数 * @param {Boolean} [data.completeZero = false] - 是否个位数补0 * @param {String} [data.dType = ' '] - 「天」后面的文字 * @param {String} [data.hType = ' '] - 「时」后面的文字 * @param {String} [data.mType = ' '] - 「分」后面的文字 * @param {String} [data.sType = ' '] - 「秒」后面的文字 */ function CountDown (data) { const _dTypeSend = (typeof data.dType !== 'undefined') && data.dType !== '' const _hTypeSend = (typeof data.hType !== 'undefined') && data.hType !== '' const _mTypeSend = (typeof data.mType !== 'undefined') && data.mType !== '' const _sTypeSend = (typeof data.sType !== 'undefined') && data.sType !== '' const _isElement = ((o) => { /* 是否为Element */ return typeof HTMLElement === 'object' ? o instanceof HTMLElement : !!o && typeof o === 'object' && o !== null && o.nodeType === 1 && typeof o.nodeName === 'string' })(data.dom) const _formatNum = (number) => { /* 格式化数字格式 */ if (number < 10 && data.completeZero) { return '0' + number } else { return number.toString() } } const _SetInterval = function (func, millisecond) { /* 周期执行 */ let _setIntervalId if (typeof func === 'function') { _setIntervalId = setTimeout(function self () { _setIntervalId = setTimeout(self, millisecond) func() }, millisecond) } this.stop = () => { clearTimeout(_setIntervalId) } } const _print = (time) => { /* 输出 */ const day = _formatNum(Math.floor((time / (24 * 60 * 60)))) const hour = _formatNum(Math.floor((time / (60 * 60)) % 24)) const minute = _formatNum(Math.floor((time / 60) % 60)) const second = _formatNum(time % 60) let text if (day != 0 || _dTypeSend) { text = day + data.dType + hour + data.hType + minute + data.mType + second + data.sType } else if (hour != 0 || _hTypeSend) { text = hour + data.hType + minute + data.mType + second + data.sType } else if (minute != 0 || _mTypeSend) { text = minute + data.mType + second + data.sType } else { text = second + data.sType } if (_isElement) { data.dom.innerHTML = text } else { console.log(text) } } if (!_dTypeSend) { data.dType = ' ' } if (!_hTypeSend) { data.hType = ' ' } if (!_mTypeSend) { data.mType = ' ' } if (!_sTypeSend) { data.sType = '' } /* 初始化时就输出一遍 */ _print(Math.round((data.deadline - Date.now()) / 1000)) const obj = new _SetInterval(() => { const time = Math.round((data.deadline - Date.now()) / 1000) if (time < (data.leftSec || 0)) { obj.stop() if (typeof data.callback === 'function') { data.callback() } return } _print(time) }, 1000) this.stop = obj.stop } /* 使用测试 */ var a = new CountDown({ deadline: Date.now() + 10000, dom: document.getElementById('j-test'), callback: () => { console.log('完成') }, leftSec: 1, completeZero: false, dType: '', hType: '小时', mType: '分', sType: '秒' }) // a.stop();
-
分开输出
/** * 显示倒计时,单独输出每一个位数(秒个位、秒十位、分个位、分十位、时个位、时十位、天) * @constructor * @param {Number} deadline - 到期的时间戳 * @param {Function} [callback] - 到点后的回调函数 * @param {Array} [DOMList] - 展示的DOM集合,前7个项有效(若存在,则从最小的时间开始展示;若不存在,则console.log) */ function CountDown ({ deadline, callback = () => {}, DOMList = [] } = {}) { /* 周期执行 */ const SetInterval = function (func, millisecond) { let setIntervalId if (typeof func === 'function') { setIntervalId = setTimeout(function self () { setIntervalId = setTimeout(self, millisecond) func() }, millisecond) } this.stop = () => { clearTimeout(setIntervalId) } } /* 秒数 -> 天、时、分、秒 */ const formatSeconds = (seconds) => { const secondArr = (seconds % 60).toString().split('') const secondObj = { second0: secondArr.pop(), // 秒的个位数 second00: secondArr.pop() || '0' // 秒的十位数 } const minuteArr = (Math.floor(seconds / 60) % 60).toString().split('') const minuteObj = { minute0: minuteArr.pop(), // 分的个位数 minute00: minuteArr.pop() || '0' // 分的十位数 } const hourArr = (Math.floor(seconds / 3600) % 24).toString().split('') const hourObj = { hour0: hourArr.pop(), // 时的个位数 hour00: hourArr.pop() || '0' // 时的十位数 } const dayObj = { day: (Math.floor(seconds / (3600 * 24))).toString() // 天的所有 } return { ...secondObj, ...minuteObj, ...hourObj, ...dayObj } } const timeMapDom = [ // 映射 DOM和时间 的顺序 'second0', // 第一个DOM -> 'second0' 'second00', 'minute0', 'minute00', 'hour0', 'hour00', 'day' ] /* 输出 */ const print = (time) => { const timeObj = formatSeconds(time) if (DOMList.length > 0) { DOMList.map((value, index) => { // 仅输出有给DOM展示的内容,多余的时间丢弃 requestAnimationFrame(() => { value.innerText = timeObj[timeMapDom[index]] }) }) } else { console.log(timeObj) } } // 初始化时就输出一遍 print(Math.round((deadline - Date.now()) / 1000)) // 每秒输出一遍 const obj = new SetInterval(() => { const time = Math.round((deadline - Date.now()) / 1000) if (time < 0) { obj.stop() if (typeof callback === 'function') { callback() } } else { print(time) } }, 1000) this.stop = obj.stop } /* 使用测试 */ var a = new CountDown({ deadline: Date.now() + 10000, callback: function () { console.log('完成') }, DOMList: [ document.getElementById('j-7'), document.getElementById('j-6'), document.getElementById('j-5'), document.getElementById('j-4'), document.getElementById('j-3'), document.getElementById('j-2'), document.getElementById('j-1') ].slice(0, Math.floor(Math.random() * 8)) // 0~7 }) // a.stop();
-
vue
-
react
/**
* 异步函数都成功返回后,执行func
* @param {Function} func
* @param {...String} url - AJAX请求的地址
*/
function multiCallback(func, url) {
if (typeof func === 'function' && arguments.length >= 2) {
var urlLength = arguments.length - 1,
handle = function () {
var self = arguments.callee;
if (self.count === urlLength) {
func.call(undefined, self.result);
}
};
handle.count = 0;
handle.result = {};
for (var i = 1; i <= urlLength; i++) {
(function (url) {
$.ajax({
url: url,
dataType: 'json',
data: {}
/*,
// Zepto默认:没有deferred的对象,用参数模式替代
success: function (data) {
handle.result[url] = data;
handle.count += 1;
handle();
}
*/
}).done(function (data) {
handle.result[url] = data;
handle.count += 1;
handle();
});
}(arguments[i]));
}
} else {
return false;
}
}
- 可以使用
Promise.all或async-await方法实现。- 可以使用jQuery的Deferred对象
$.when($.ajax()...).done(成功后方法),完全替代。
function extend(target, options) {
var copy, name;
for (name in options) {
copy = options[name];
if (Object.prototype.toString.call(copy) === '[object Array]') {
target[name] = arguments.callee([], copy);
} else if (Object.prototype.toString.call(copy) === '[object Object]') {
target[name] = arguments.callee(target[name] ? target[name] : {}, copy);
} else {
target[name] = options[name];
}
}
return target;
}
- 可以使用lodash的
_.assign(object, [sources])(浅复制)、_.merge(object, [sources])(深复制),完全替代。- 可以使用deepmerge,完全替代。
- 可以使用jQuery的
$.extend(对象1, 对象2),完全替代。
/**
* 通过类名获取一组元素
* @param {String} className - 类名
* @param {Object} [parentDom = document] - 父级DOM
* @returns {Array} - 类名匹配的DOM数组
*/
function getElementsByClassName(className, parentDom) {
parentDom = parentDom || document;
className = className.replace(/(^\s+)|(\s+$)/g, ''); // 去除前后空格
if (document.getElementsByClassName) { /* ie9+ */
return parentDom.getElementsByClassName(className);
} else if (document.querySelectorAll) { /* ie8+ */
className = '.' + className.split(/\s+/).join('.');
return parentDom.querySelectorAll(className);
} else {
var doms = parentDom.getElementsByTagName('*'),
nameArr = className.split(/\s+/),
nameLen = nameArr.length,
domArr = [],
i, len, j, regex;
for (i = 0, len = doms.length; i < len; i++) { /* 遍历所有标签 */
for (j = 0; j < nameLen; j++) { /* 遍历类名 */
regex = new RegExp('\\b' + nameArr[j] + '\\b');
if (!regex.test(doms[i].className)) {
break;
}
}
if (j >= nameLen) {
domArr.push(doms[i]);
}
}
return domArr;
}
}可以使用jQuery的
$('.类名'),完全替代。
参考:MDN:cookie。
var cookieFuc = {
/**
* 读取一个cookie的值
* @param {String} key - 名
* @returns {String|Null} - 值 或 null
*/
getItem: function (key) {
if (!key) {
return null;
} else {
return decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
}
},
/**
* 新建或更新一个cookie
* @param {String} key - 名
* @param {String} value - 值
* @param {Number|Date|String|Infinity} [deadline] - 过期时间。默认:关闭浏览器后过期
* @param {String} [path] - 路径。默认:当前文档位置的路径
* @param {String} [domain] - 域名。默认:当前文档位置的路径的域名部分
* @param {Boolean} [secure] - 是否「仅通过https协议传输」。默认:否
* @param {String} [samesite] - SameSite,取值:Strict、Lax。默认:无
* @param {String} [priority] - 优先级,取值;Low、Medium、High。默认:Medium
* @returns {Boolean} - 操作成功或失败
*/
setItem: function (key, value, deadline, path, domain, secure, samesite, priority) {
if (!key || (window.location.protocol === 'http:' && secure)) { // fixme: 更多设置cookie失败的情况
return false;
} else {
var expires = "";
if (deadline) {
switch (deadline.constructor) {
case Number:
expires = deadline === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + deadline;
break;
case String:
expires = "; expires=" + deadline;
break;
case Date:
expires = "; expires=" + deadline.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(key) + "=" + encodeURIComponent(value) + expires + (domain ? "; domain=" + domain : "") + (path ? "; path=" + path : "") + (secure ? "; secure" : "") + (samesite ? "; samesite=" + samesite : "") + (priority ? "; priority=" + priority : "");
return true;
}
},
/**
* 删除一个cookie
* @param {String} key - 名
* @param {String} [path] - 路径。默认:当前文档位置的路径
* @param {String} [domain] - 域名。默认:当前文档位置的路径的域名部分
* @returns {Boolean} - 操作成功或失败
*/
removeItem: function (key, path, domain) {
if (!key || !this.hasItem(key)) {
return false;
} else {
document.cookie = encodeURIComponent(key) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + ( domain ? '; domain=' + domain : '') + ( path ? '; path=' + path : '');
return true;
}
},
/**
* 检查一个cookie是否存在
* @param {String} key - 名
* @returns {Boolean} - 存在与否
*/
hasItem: function (key) {
if (!key) {
return false;
} else {
return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(document.cookie);
}
},
/**
* 返回cookie名字的数组
* @returns {Array} - 名的数组 或 []
*/
listItems: function () {
if (document.cookie === '') {
return [];
} else {
var keys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/),
i, len;
for (i = 0, len = keys.length; i < len; i++) {
keys[i] = decodeURIComponent(keys[i]);
}
return keys;
}
},
/**
* 清空所有cookie
* @returns {Boolean} - 操作成功或失败
*/
clear: function () {
if (document.cookie === '') {
return false;
} else {
var keys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/),
i, len;
for (i = 0, len = keys.length; i < len; i++) {
this.removeItem(decodeURIComponent(keys[i]));
}
return true;
}
}
};可以使用js-cookie,完全替代。
/**
* 获取URL相关信息
* @param {String} [url = window.location.href] - URL
* @returns {Object} location - 包括:href、protocol、hostname、port、pathname、search、searchObj、hash 的对象。若不是合法URL,返回false
*/
function getLocation(url = window.location.href) {
try {
/* 为了方便阅读 */
const protocolStr = /^(?:([A-Za-z]+):)?/.source
const slashStr = /\/*/.source
const hostnameStr = /([0-9A-Za-z.-]+)/.source
const portStr = /(?::(\d+))?/.source
const pathnameStr = /(\/[^?#]*)?/.source
const searchStr = /(?:\?([^#]*))?/.source
const hashStr = /(?:#(.*))?$/.source
const regex = new RegExp(protocolStr + slashStr + hostnameStr + portStr + pathnameStr + searchStr + hashStr, 'g');
const regexArr = regex.exec(url);
const keyArr = [ 'href', 'protocol', 'hostname', 'port', 'pathname', 'search', 'hash' ];
const location = { 'searchObj': {} };
keyArr.forEach(function (item, index) {
location[item] = regexArr[index] || ''
})
const searchArr = location['search'].split('&')
for (let i = 0; i < searchArr.length; i++) {
if (searchArr[i] !== '') {
const searchItem = searchArr[i].split('=')
const key = searchItem.shift()
const value = searchItem.join('=')
if (!Object.prototype.hasOwnProperty.call(location['searchObj'], key)) { // 用第一次出现的
location['searchObj'][key] = value
}
}
}
return location
} catch (e) { // 不是合法URL
return false
}
}参考:用正则表达式分析 URL。
可以使用
new URL(location.href),完全替代。
获取某search值:
/** * 获取某search值 * @param {String} checkKey - search的key * @param {String} [search = window.location.search] - search总字符串(不校验) * @returns {String|Boolean} - search的value 或 不存在false */ function getSearchValue (checkKey, search = window.location.search) { checkKey = checkKey.toString() if (search.slice(0, 1) === '?') { search = search.slice(1) } for (let i = 0, searchArr = search.split('&'); i < searchArr.length; i++) { if (searchArr[i] !== '') { const tempArr = searchArr[i].split('=') const key = tempArr.shift() const value = tempArr.join('=') if (key === checkKey) { return decodeURIComponent(value) } } } return false }可以使用
new URLSearchParams(location.search).get(search的key),完全替代。拼接接口URL时,可以在路由最后添加
?并且加上一些固定不变的search参数,在使用URL时候都以&参数=值的形式添加额外参数:
xxx/xxx?&a=1可以正常解析const api1 = 'xxx/xxx?' const api2 = 'xxx/xxx?v=1.0' // 使用时 url1 = api1 + '&a=1' + '&b=2' + '&c=3' url2 = api2 + '&a=1' + '&b=2' + '&c=3'
-
批量修改(未加
encodeURIComponent)对象转换为
a=1&b=2:Object.entries(对象).map((val) => val.join('=')).join('&')。/** * 在URL末尾修改search键-值 * @param {String} [url = window.location.href] - URL * @param {Object} searchObj - 修改的search键-值(若key-value的value设置为`false`,则删除这个key) * @returns {String} - 修改完毕的URL */ function changeUrlSearch(url: string = window.location.href, searchObj: Record<string, string | false> = {}): string { if (Object.keys(searchObj).length === 0) { // 空对象不处理 return url; } const hashIndex = url.includes("#") ? url.indexOf("#") : url.length; // "#"所在的字符串位置索引 const urlWithoutHash = url.slice(0, hashIndex); // 去除hash后的url const searchIndex = urlWithoutHash.indexOf("?"); // "?"所在的字符串位置索引 // 把原始search值写入对象 const originalSearchObj: Record<string, string> = {}; if (searchIndex !== -1) { const search = urlWithoutHash.slice(searchIndex + 1); // search值(不包括 ?) // 写入已存在search的键-值 const searchArr = search.split("&"); for (let i = 0; i < searchArr.length; i++) { if (searchArr[i] !== "") { const searchItem = searchArr[i].split("="); const key = searchItem.shift() as string; const value = searchItem.join("="); // 兜底有些值包含"=" if (!Object.prototype.hasOwnProperty.call(originalSearchObj, key)) { // 用第一次出现的 originalSearchObj[key] = value; } } } } // 合并原始search和新增search(同名覆盖) const newSearchObj: Record<string, string | false> = Object.assign({}, originalSearchObj, searchObj); // 生成新的合并过后的search字符串 const newSearch = Object.entries(newSearchObj) // 值为`false`的key被删除 .filter(([key, value]) => { return value !== false; }) .map((val) => { return val.join("="); }) .join("&"); const hash = url.slice(hashIndex); // 原始hash let urlWithoutSearch; // 去除search、hash后的url if (searchIndex !== -1) { urlWithoutSearch = urlWithoutHash.slice(0, searchIndex); } else { urlWithoutSearch = urlWithoutHash; } return urlWithoutSearch + (newSearch ? `?${newSearch}` : "") + hash; }
-
单个修改
/** * 在URL末尾修改search键-值 * @param {String} url - URL * @param {String} name - 名 * @param {String|Boolean} value - 值(若传`false`则删除属性名) * @returns {String} - 添加完毕的URL */ function changeUrlSearch (url, name, value) { if (!name) { return url } var hashIndex = url.includes('#') ? url.indexOf('#') : url.length var urlWithoutHash = url.slice(0, hashIndex) var hash = url.slice(hashIndex) var searchIndex = urlWithoutHash.indexOf('?') if (searchIndex === -1) { if (value === false) { return url } return urlWithoutHash + '?' + encodeURIComponent(name) + '=' + encodeURIComponent(value) + hash } else if (searchIndex === urlWithoutHash.length - 1) { if (value === false) { return url.slice(0, urlWithoutHash.length - 1) + hash } return urlWithoutHash + encodeURIComponent(name) + '=' + encodeURIComponent(value) + hash } else { const urlWithoutSearch = urlWithoutHash.slice(0, searchIndex) const search = urlWithoutHash.slice(searchIndex + 1) const originalSearchObj = {} // 写入已存在search的键-值 const searchArr = search.split('&') for (let i = 0; i < searchArr.length; i++) { if (searchArr[i] !== '') { const searchItem = searchArr[i].split('=') const key = searchItem.shift() const value = searchItem.join('=') if (!Object.prototype.hasOwnProperty.call(originalSearchObj, key)) { // 用第一次出现的 originalSearchObj[key] = value } } } let newSearch if (value === false) { delete originalSearchObj[name] newSearch = Object.entries(originalSearchObj) .map((val) => { return val.join('=') }) .join('&') } else { const newSearchObj = Object.assign({}, originalSearchObj, { [encodeURIComponent(name)]: encodeURIComponent(value) }) newSearch = Object.entries(newSearchObj) .map((val) => { return val.join('=') }) .join('&') } return urlWithoutSearch + (newSearch ? `?${newSearch}` : '') + hash } }
可以使用
var a = new URLSearchParams('?s=url&a=1&b=2&c'); a.set('d', '4'); a.delete('b'); a.toString(),完全替代。
/**
* 滚动到x、y轴指定位置
* @param {Number} endX - 到达x轴像素
* @param {Number} endY - 到达y轴像素
* @param {Number} time - 所用毫秒
*/
function animateTo(endX, endY, time) {
var scrollFromX = document.body.scrollLeft || document.documentElement.scrollLeft,
scrollFromY = document.body.scrollTop || document.documentElement.scrollTop,
scrollToX = endX > document.documentElement.scrollWidth ? document.documentElement.scrollWidth : endX,
scrollToY = endY > document.documentElement.scrollHeight ? document.documentElement.scrollHeight : endY,
i = 0,
runEvery = 5,
myself = arguments.callee;
time /= runEvery;
clearInterval(myself.setIntervalId);
myself.setIntervalId = setInterval(function () {
i += 1;
window.scrollTo((scrollToX - scrollFromX) / time * i + scrollFromX, (scrollToY - scrollFromY) / time * i + scrollFromY);
if (i >= time) {
clearInterval(myself.setIntervalId);
}
}, runEvery);
}
使用velocity动画库(中文文档)做所有的动画(包括JS和CSS)才是最简单且性能最佳的选择。
如:滚动到某位置
$('html').velocity('scroll', {offset: y轴像素, duration: 毫秒});。原生js已支持:支持顺滑滚动,但不支持设定滚动时间
window.scroll/scrollTo(横轴坐标, 纵轴坐标)或window.scroll/scrollTo({ left: 横轴坐标, top: 纵轴坐标, behavior: 'smooth'或'auto' })window.scrollBy(相对横轴坐标, 相对纵轴坐标)或window.scrollBy({ left: 相对横轴坐标, top: 相对纵轴坐标, behavior: 'smooth'或'auto' })
-
构造函数
-
普通版:
var OneConstructor = function () { /* 私有的内容 */ var _para = {a: '私有的变量_para'}, _func = function () { console.log('私有的业务逻辑_func', _para); }, _bindEvent = function () { /* 绑定事件 */ }, _init = function () { /* 初始化 */ _func(); _bindEvent(); }; _init(); for (var _arr = [], _i = 0; _i < arguments.length; _i++) { _arr.push(arguments[_i]); } /* 公开的内容 */ this.para = _arr; this.para_1 = {b: '公开的变量para_1(每个实例不共享)'}; this.func_1 = function () { console.log('公开的业务逻辑func_1(每个实例不共享)'); }; };
-
修改构造函数的原型对象(所有实例都共享):
var OneConstructor = (function () { /* 私有的内容 */ var _para = {a: '私有的变量_para'}, _func = function () { console.log('私有的业务逻辑_func', _para); }, _bindEvent = function () { /* 绑定事件 */ }, _init = function () { /* 初始化 */ _func(); _bindEvent(); }; function Constructor() { _init(); for (var _arr = [], _i = 0; _i < arguments.length; _i++) { _arr.push(arguments[_i]); } /* 公开的内容 */ this.para = _arr; this.para_1 = {b: '公开的变量para_1(每个实例不共享)'}; this.func_1 = function () { console.log('公开的业务逻辑func_1(每个实例不共享)'); }; } /* 构造函数的原型对象上,每个实例共享 */ Constructor.prototype = { para_2: {c: '公开的变量para_2(每个实例共享)'}, func_2: function () { console.log('公开的业务逻辑func_2(每个实例共享)'); } }; /* 原型对象添加constructor属性 */ if (typeof Object.defineProperty === 'function') { /* 使属性:不可以改变描述符、不可以删除、不可以枚举、不可以被赋值运算符改变 */ Object.defineProperty(Constructor.prototype, 'constructor', { value: Constructor }); } else { Constructor.prototype.constructor = Constructor; } return Constructor; }());
-
-
模块模式(单例模式+私有变量和特权方法)
var singletonObj = (function () { /* 私有变量和私有方法,无法直接访问,只能由return的对象字面量访问 */ var _para = {a: '私有变量'}, _func = function () { console.log('私有方法'); }; /* 单例模式,可以访问私有内容 */ return { get: function () { /* 特权方法 */ _func(); return _para; }, set: function (para) { /* 特权方法 */ _func(); _para = para; }, para: {b: '公开对象'}, func: function () { console.log('公开方法'); } } }());
单例模式:
var singletonObj = { para: {}, func: function () {} };
来自:rAF.js。
(function () {
var lastTime = 0,
vendors = ['ms', 'moz', 'webkit', 'o'],
x;
for (x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime(),
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
id = window.setTimeout(function () {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
}
}());if (typeof Date.now !== 'function') {
Date.now = function () {
return new Date().getTime();
};
}
Date.now()相对于new Date().getTime()及其他方式,可以避免生成不必要的Date对象,更高效。
if (!Array.isArray) {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (Object.prototype.toString.call(callback) != '[object Function]') {
throw new TypeError(callback + ' is not a function');
}
if (thisArg) {
T = thisArg;
}
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
A[k] = mappedValue;
}
k += 1;
}
return A;
};
}if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== 'function') {
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {
},
fBound = function () {
return fToBind.apply(this instanceof fNOP
? this
: oThis || this,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
}if (!String.prototype.repeat) {
String.prototype.repeat = function (count) {
'use strict';
if (this == null) {
throw new TypeError('can\'t convert ' + this + ' to object');
}
var str = '' + this;
count = +count;
if (count != count) {
count = 0;
}
if (count < 0) {
throw new RangeError('repeat count must be non-negative');
}
if (count == Infinity) {
throw new RangeError('repeat count must be less than infinity');
}
count = Math.floor(count);
if (str.length == 0 || count == 0) {
return '';
}
// 确保 count 是一个 31 位的整数。这样我们就可以使用如下优化的算法。
// 当前(2014年8月),绝大多数浏览器都不能支持 1 << 28 长的字符串,所以:
if (str.length * count >= 1 << 28) {
throw new RangeError('repeat count must not overflow maximum string size');
}
var rpt = '';
for (; ;) {
if ((count & 1) == 1) {
rpt += str;
}
count >>>= 1;
if (count == 0) {
break;
}
str += str;
}
return rpt;
};
}来自:MDN:Number.isNaN。
Number.isNaN = Number.isNaN || function (value) {
return typeof value === 'number' && isNaN(value);
};Number.isFinite = Number.isFinite || function (value) {
return typeof value === 'number' && isFinite(value);
};Number.isInteger = Number.isInteger || function (value) {
return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
};Number.isSafeInteger = Number.isSafeInteger || function (value) {
return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
};