您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
NS库,强大的扩展
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/376730/662553/NS%E5%BA%93.js
// ==UserScript== // @name NS库 // @namespace http://tampermonkey.net/ // @version 0.1 // @description NS库,强大的扩展 // @author lnwazg // @grant none // ==/UserScript== (function (window) { "use strict"; var NS = { //属性表 //浏览器判断 browser: { //判断浏览器类型 versions: (function () { var u = navigator.userAgent, app = navigator.appVersion; return { //是否是以下类型的浏览器 iOS: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, iPhone: u.indexOf('iPhone') > -1, iPad: u.indexOf('iPad') > -1, IE: (!!window.ActiveXObject || "ActiveXObject" in window || u.indexOf("MSIE") >= 1), Firefox: (u.indexOf("Firefox") != -1), Chrome: (u.indexOf("Chrome") != -1), Safari: (u.indexOf("Safari") != -1) }; })() }, //localStorage方便的操作类 LS: { set: function (key, value) { //在iPhone/iPad上有时设置setItem()时会出现诡异的QUOTA_EXCEEDED_ERR错误 //这时一般在setItem之前,先removeItem()就ok了 if (this.get(key) !== null) this.remove(key); localStorage.setItem(key, value); }, //查询不存在的key时,有的浏览器返回undefined,这里统一返回null get: function (key) { var v = localStorage.getItem(key); return v === undefined ? null : v; }, remove: function (key) { localStorage.removeItem(key); }, clear: function () { localStorage.clear(); }, each: function (fn) { var n = localStorage.length, i = 0, fn = fn || function () {}, key; for (; i < n; i++) { key = localStorage.key(i); if (fn.call(this, key, this.get(key)) === false) break; //如果内容被删除,则总长度和索引都同步减少 if (localStorage.length < n) { n--; i--; } } } }, //TODO: 其它新增属性可添加于此 //函数表 //localStorage操作的快捷方式 lset: function () { this.LS.set.apply(this.LS, arguments); }, lget: function () { this.LS.get.apply(this.LS, arguments); }, lremove: function () { this.LS.remove.apply(this.LS, arguments); }, lclear: function () { this.LS.clear.apply(this.LS, arguments); }, leach: function () { this.LS.each.apply(this.LS, arguments); }, //读取cookies getCookie: function (name) { var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); if (arr = document.cookie.match(reg)) { return unescape(arr[2]); } else { return null; } }, /** * 动态获取cookie的域的方法<br> * 该方法可作为适配器方法 */ getCookieDomain: function () { //首先你应该预置一个NS.cookieDomainFn的函数,否则将使用空默认值 // return (NS.cookieDomain? (";domain="+ NS.cookieDomain):""); return (NS.cookieDomainFn ? (";domain=" + NS.cookieDomainFn()) : ""); }, /** * 写cookies * name键 * value值 */ setCookie: function (name, value, expireDays) { //(默认为永远不过期)写入之后有效期设置为100年,也就是相当于永不过期 var Days = 36000; if (expireDays) { //假如传了过期时间这个参数 Days = expireDays; } var exp = new Date(); exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000); //设置cookie的键值对信息以及过期信息 (指定path真的很重要!) document.cookie = (name + "=" + escape(value) + ";expires=" + exp.toGMTString() + ";path=/" + this.getCookieDomain()); }, //写cookie。该cookie的生命周期为:session setCookieInSession: function (name, value) { var isIE = !-[1, ]; //判断是否是ie核心浏览器 if (isIE) { //设置cookie的键值对信息以及过期信息 (指定path真的很重要!) document.cookie = (name + "=" + escape(value) + ";expires=At the end of the Session;path=/" + this.getCookieDomain()); } else { //设置cookie的键值对信息以及过期信息 (指定path真的很重要!) document.cookie = (name + "=" + escape(value) + ";expires=Session;path=/" + this.getCookieDomain()); } }, //删除cookies delCookie: function (name) { var exp = new Date(); exp.setTime(exp.getTime() - 1); //将过期时间设置为上一毫秒 var cval = this.getCookie(name); if (cval != null) { //若能取到这个cookie的键值对,那么就将其设置为过期 (指定path真的很重要!) document.cookie = (name + "=" + cval + ";expires=" + exp.toGMTString() + ";path=/" + this.getCookieDomain()); } }, //删除cookies,未指定域名的 delCookieWithoutDomain: function (name) { var exp = new Date(); exp.setTime(exp.getTime() - 1); //将过期时间设置为上一毫秒 var cval = this.getCookie(name); if (cval != null) { //若能取到这个cookie的键值对,那么就将其设置为过期 (指定path真的很重要!) document.cookie = (name + "=" + cval + ";expires=" + exp.toGMTString() + ";path=/"); } }, //判断某个字符串是否为空 isNull: function (obj) { if (!obj || obj.length == 0) { return true; } return false; }, //判断是否为空 isEmpty: function (obj) { return this.isNull(obj); }, /** * 是否不为空 */ isNotEmpty: function (obj) { return !this.isNull(obj); }, //某个数组中是否包含某个元素 contains: function (element, array) { if (this.indexOf(element, array) != -1) { return true; } return false; }, /** * 更适用于对象比较的版本 * @param element * @param array */ objContains: function (element, array) { if (this.objIndexOf(element, array) != -1) { return true; } return false; }, //返回某个元素在数组中的位置 indexOf: $.inArray, /** * 更适用于对象比较的版本<br> * 将每个元素分别转换成string之后再进行查找。(此种查找方法适用于复杂对象的查找,并且那种情况下indexOf()方法将会失效) */ objIndexOf: function (element, array) { var eleNew = JSON.stringify(element); var arrayNew = []; for (var i = 0; i < array.length; i++) { arrayNew[i] = JSON.stringify(array[i]); } return this.indexOf(eleNew, arrayNew); }, /** * 删除数组中某个索引的数据 * @param idx * @param array * @returns */ removeIdx: function (idx, array) { if (isNaN(idx) || idx > array.length) { return false; } for (var i = 0, n = 0; i < array.length; i++) { if (array[i] != array[idx]) { array[n++] = array[i]; } } array.length -= 1; //如果数组已经没元素了,再删除就会报错! return array; }, /** * 更适用于对象比较的版本 * @param idx * @param array * @returns */ objRemoveIdx: function (idx, array) { return this.removeIdx(idx, array); }, /** * 删除数组中的某个元素 * @param element * @param array * @returns */ removeElement: function (element, array) { return this.removeIdx(this.indexOf(element, array), array); }, /** * 更适用于对象比较的版本<br> * 删除数组中的某个元素 * @param element * @param array * @returns */ objRemoveElement: function (element, array) { return this.objRemoveIdx(this.objIndexOf(element, array), array); }, /** * 判断某个字符串是不是以某个字符串开头 * 为何要写这个方法?因为令人无语的微信浏览器竟然不支持该方法啊!!! * @param original 原有的字符串 * @param str 待搜索的字符串 * @returns {Boolean} */ startsWith: function (original, str) { if (str == null || str == "" || original.length == 0 || str.length > original.length) { return false; } if (original.substr(0, str.length) == str) { return true; } else { return false; } return true; }, /** * 判断某个字符串是不是以某个字符串结尾 * @param original * @param str * @returns {Boolean} */ endWith: function (original, str) { if (str == null || str == "" || original.length == 0 || str.length > original.length) { return false; } if (original.substring(original.length - str.length) == str) { return true; } else { return false; } return true; }, //返回短名称 shortName: function (str, maxLength) { if (str && str.length > 0) { var len = str.length; if (len <= maxLength) { return str; } else { return (str.substr(0, maxLength) + "..."); } } else { return ""; } }, //检查是否是数字 checkNumber: function (value) { var reg = /^[1-9]\d*$/; if ("0" == value || reg.test(value)) { return true; } else { return false; } }, //将指定map的指定的key初始化成空array initMapArray: function () { var len = arguments.length; //可变参数的方法 if (len == 0 || len == 1) { return; } var map = arguments[0]; for (var i = 1; i < arguments.length; i++) { var paramName = arguments[i]; map[paramName] = []; } }, //匿名 anoym: function (name) { if (!name || name.length == 0) { return "***"; } var length = name.length; if (length == 1) { return (name + "***"); } else { return (name[0] + "***" + name[name.length - 1]); } }, /** * 动态加载脚本 * 不推荐使用,因为这样加载的脚本会到最后才执行。如果该脚本被其他脚本依赖,则不推荐这样的方式 * @param script */ loadScript: function (url) { var content = '<script type="text/javascript" src="' + url + '"></script>'; document.writeln(content); }, /** * 动态加载样式 * @param url */ loadCss: function (url) { var content = '<link rel="stylesheet" type="text/css" href="' + url + '"/>'; document.writeln(content); }, //转换为用于显示用的字符串(去除undefined等等不合理的显示) toStr: function (obj) { if (this.isNull(obj)) { return ""; } return obj; }, //兼容方式获取滚动条距离顶部的距离 getScrollTop: function () { var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop; return scrollTop; }, //兼容方式设置滚动条距离顶部的距离 setScrollTop: function (scroll_top) { document.documentElement.scrollTop = scroll_top; window.pageYOffset = scroll_top; document.body.scrollTop = scroll_top; }, /** * 获取两个日期的天数差(起始时间-结束时间) */ getDateDiffDays: function (startDate, endDate) { var startTime = new Date(Date.parse(startDate.replace(/-/g, "/"))).getTime(); //得到毫秒数 var endTime = new Date(Date.parse(endDate.replace(/-/g, "/"))).getTime(); var dates = Math.abs((startTime - endTime)) / (1000 * 60 * 60 * 24); //取绝对值 return dates; }, //防重复提交的事件注册表 //用于检测某个事件是否已经在队列里先行一步了 _timerReg: {}, /** * 防止快速点击所导致的重复提交 * @param id 标记,用于区分是否是同一种业务场景 * @param fn 回调函数 * @param wait 等待的毫秒数 * @returns */ preventDuplicateSubmission: function (id, fn, wait) { if (!wait) { wait = 300; //默认延迟时间是300毫秒 } if (NS._timerReg[id]) { console.log("检测到重复点击..."); window.clearTimeout(NS._timerReg[id]); delete NS._timerReg[id]; } return NS._timerReg[id] = window.setTimeout(function () { fn(); delete NS._timerReg[id]; }, wait); }, /** * 将对象保存到localStorage * @param key * @param obj */ saveLocalStorageObj: function (key, obj) { if (localStorage) { localStorage[key] = JSON.stringify(obj); } }, /** * 从localStorage读取出对象 * @param key */ readLocalStorageObj: function (key) { if (localStorage && localStorage[key]) { if (NS.isNotEmpty(localStorage[key])) { return JSON.parse(localStorage[key]); } } return null; }, /** * 指定的Url中,如果不存在某个参数,则添加该参数 */ appendUrlParamIfNotExist: function (url, name, value) { if (!this.urlHasParam(url, name)) { //没有参数,则加上参数。有参数,则什么都不做 url = this.urlAppendParam(url, name, value); } return url; }, /** * 给指定的url增加参数 * @param url * @param name * @param value */ urlAppendParam: function (url, name, value) { url += ((url.indexOf("?") == -1 ? "?" : "&") + name + "=" + value); return url; }, //某个url中,是否含有某个参数 urlHasParam: function (url, name) { var paramArray = this.getUrlParamArray(url); if (this.contains(name, paramArray)) { return true; } else { return false; } }, /** * 获取指定URL的参数的数组 * 只要是在这个URL中出现过的参数,都可以算在里面 * @param url * @returns {Object} */ getUrlParamArray: function (url) { var retArray = []; if (url.indexOf("?") != -1) { var str = url.substr(url.indexOf("?") + 1); strs = str.split("&"); for (var i = 0; i < strs.length; i++) { // theRequest[strs[i].split("=")[0]]=(strs[i].split("=")[1]); retArray.push(strs[i].split("=")[0]); } } return retArray; }, /** * 替换所有字符 * @param str * @param reallyDo 想要替换的 * @param replaceWith 替换成的 * @param ignoreCase 是否忽略大小写 * @returns */ replaceAll: function (str, reallyDo, replaceWith, ignoreCase) { if (!RegExp.prototype.isPrototypeOf(reallyDo)) { return str.replace(new RegExp(reallyDo, (ignoreCase ? "gi" : "g")), replaceWith); } else { return str.replace(reallyDo, replaceWith); } }, /** * 为文字包裹上一层颜色 */ wrapperColor: function (original, color) { return "<font color='" + color + "'>" + original + "</font>"; }, /** * 将毫秒数格式化成正常显示的格式 */ formatDateMillsToShow: function (millseconds) { if (this.isEmpty(millseconds)) { return ""; } return (new Date(millseconds)).format("yyyy-MM-dd hh:mm:ss"); }, formatDateMillsToShowDate: function (millseconds) { if (this.isEmpty(millseconds)) { return ""; } return (new Date(millseconds)).format("yyyy-MM-dd"); }, /** * 一个闭包计数器工厂<br> * 默认从1开始计数<br> * 可以自己指定开始的计数值 * @param startNum * @returns {Function} */ counterFnFactory: function (startNum) { var num = 1; if (typeof startNum !== 'undefined') { num = Number(startNum); } //获取下一个数(默认返回的方法) var getNextNumFn = function () { return num++; } return getNextNumFn; }, /** * dom中是否存在某个selector<br> * 可以存在一个或者多个 * @param selector * @returns {Boolean} */ existsDomNode: function (selector) { return $(selector).get().length > 0; }, /** * dom中是否有且只存在一个某个selector * @param selector * @returns {Boolean} */ existsOnlyOneDomNode: function (selector) { return $(selector).get().length == 1; }, /** * 将数字格式转换成千分位 *@param{Object}num */ commafy: function (num) { if ((num + "").trim() == "") { return ""; } if (isNaN(num)) { return ""; } num = num + ""; if (/^.*\..*$/.test(num)) { var pointIndex = num.lastIndexOf("."); var intPart = num.substring(0, pointIndex); var pointPart = num.substring(pointIndex + 1, num.length); intPart = intPart + ""; var re = /(-?\d+)(\d{3})/ while (re.test(intPart)) { intPart = intPart.replace(re, "$1,$2") } num = intPart + "." + pointPart; } else { num = num + ""; var re = /(-?\d+)(\d{3})/ while (re.test(num)) { num = num.replace(re, "$1,$2") } } return num; }, /** * 对千分位货币值去除千分位 *@param{Object}num */ delcommafy: function (num) { if ((num + "").trim() == "") { return ""; } num = num.replace(/,/gi, ''); return num; }, /** * 获取用户识别码<br> * 该识别码每次调用的返回值均不相同<br> * 该功能主要服务于统一登录系统,用于获取验证码的凭证 * @returns */ getIdentity: function () { var s = []; var hexDigits = "0123456789abcdef"; for (var i = 0; i < 36; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); } s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the // clock_seq_hi_and_reserved // to 01 s[8] = s[13] = s[18] = s[23] = "-"; var uid = s.join(""); var identity = window.Base64.encode(uid); NS.currentIdentity = identity; //设置系统当前的识别码 return identity; }, getCurrentIdentity: function () { return NS.currentIdentity; }, /** * 绑定系统的回车事件 * @param fn */ bindGlobalEnterEvent: function (fn) { $(document).keypress(function (e) { if (e.which == 13) { fn(); } }); }, //从页面上提取数据到对象中 getPageValueToObj: function (obj, toHandleArray) { // var toHandleArray = ['insure_sex_limit','insure_min_age','insure_min_age_unit','insure_max_age','insure_max_age_unit']; // //获取页面中的字段信息 //// obj.insure_sex_limit = $.trim($("#insure_sex_limit").val()); //// obj.insure_min_age= $.trim($("#insure_min_age").val()); //// obj.insure_min_age_unit= $.trim($("#insure_min_age_unit").val()); //// obj.insure_max_age= $.trim($("#insure_max_age").val()); //// obj.insure_max_age_unit= $.trim($("#insure_max_age_unit").val()); if (obj && toHandleArray) { toHandleArray.forEach(function (e) { obj[e] = $.trim($("#" + e).val()); }); return obj; } else { return null; } }, //将对象的属性值设置到页面中 setObjPropToPageValue: function (extraData, toHandleArray) { if (extraData && toHandleArray) { toHandleArray.forEach(function (e) { $("#" + e).val(extraData[e]); }); } }, //获取某个字符串的hashCode getHashCode: function (str, caseSensitive) { if (!caseSensitive) { str = str.toLowerCase(); } // 1315423911=b'1001110011001111100011010100111' var hash = 1315423911, i, ch; for (i = str.length - 1; i >= 0; i--) { ch = str.charCodeAt(i); hash ^= ((hash << 5) + ch + (hash >> 2)); } return (hash & 0x7FFFFFFF); }, getCurrentDate: function () { return (new Date()).format("yyyy-MM-dd"); }, getCurrentDateTime: function () { return (new Date()).format("yyyy-MM-dd hh:mm:ss"); }, //日志模块 //日志开关 __isLogDebug__: true, //关闭日志开关 disableLog: function () { NS.__isLogDebug__ = false; }, enableLog: function () { NS.__isLogDebug__ = true; }, //简易日志模块 log: function () { if (NS.__isLogDebug__ && arguments.length > 0) { console.log.apply(console, arguments); } }, //base64加解密 base64encode: function (input) { var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; input = escape(input); var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0; do { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length); return output; }, base64decode: function (input) { var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0; // remove all characters that are not A-Z, a-z, 0-9, +, /, or = var base64test = /[^A-Za-z0-9\+\/\=]/g; if (base64test.exec(input)) { alert("There were invalid base64 characters in the input text.\n" + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/', and '='\n" + "Expect errors in decoding."); } input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); do { enc1 = keyStr.indexOf(input.charAt(i++)); enc2 = keyStr.indexOf(input.charAt(i++)); enc3 = keyStr.indexOf(input.charAt(i++)); enc4 = keyStr.indexOf(input.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length); return unescape(output); }, //localStorage数据导入导出 //TODO json支持、垫片技术 exportLocalStorageData: function () { console.log("开始导出localStorage配置信息...") var obj = {}; NS.LS.each(function (k, v) { obj[k] = v; }); return NS.base64encode(JSON.stringify(obj)); }, importLocalStorageData: function (input) { console.log("开始导入localStorage配置信息...") var jsonStr = NS.base64decode(input); var obj = JSON.parse(jsonStr); // NS.LS.clear(); Object.keys(obj).forEach(function (k) { NS.LS.set(k, obj[k]); }); }, //TODO: 其它新增函数可添加于此 //语言扩展表 _ext: { /** * js语言级别的扩展 */ jsLangExt: function () { //为IE浏览器补丁begin=============================== //兼容IE8、IE9等低版本浏览器找不到console对象的写法 window.console = window.console || (function () { var c = {}; c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile = c.clear = c.exception = c.trace = c.assert = function () {}; return c; })(); if (NS.browser.versions.IE) { console.log("检测到IE浏览器..."); } //console.log("加载扩展[jsLangExt]"); if (!window.getComputedStyle) { window.getComputedStyle = function (el, pseudo) { this.el = el; this.getPropertyValue = function (prop) { var re = /(\-([a-z]){1})/g; if (prop == 'float') prop = 'styleFloat'; if (re.test(prop)) { prop = prop.replace(re, function () { return arguments[2].toUpperCase(); }); } return el.currentStyle[prop] ? el.currentStyle[prop] : null; } return this; } } if (!Array.prototype.forEach) { Array.prototype.forEach = function (fun /*, thisp*/ ) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) fun.call(thisp, this[i], i, this); } }; } if (!Array.prototype.some) { Array.prototype.some = function (fun /*, thisArg */ ) { 'use strict'; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== 'function') throw new TypeError(); var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t && fun.call(thisArg, t[i], i, t)) return true; } return false; }; } if (!Array.prototype.every) { Array.prototype.every = function (fun /*, thisArg */ ) { 'use strict'; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== 'function') throw new TypeError(); var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t && !fun.call(thisArg, t[i], i, t)) return false; } return true; }; } // Production steps of ECMA-262, Edition 5, 15.4.4.19 // Reference: http://es5.github.io/#x15.4.4.19 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'); } // 1. Let O be the result of calling ToObject passing the |this| // value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal // method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 1) { T = thisArg; } // 6. Let A be a new array created as if by the expression new Array(len) // where Array is the standard built-in constructor with that name and // len is the value of len. A = new Array(len); // 7. Let k be 0 k = 0; // 8. Repeat, while k < len while (k < len) { var kValue, mappedValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the HasProperty internal // method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then if (k in O) { // i. Let kValue be the result of calling the Get internal // method of O with argument Pk. kValue = O[k]; // ii. Let mappedValue be the result of calling the Call internal // method of callback with T as the this value and argument // list containing kValue, k, and O. mappedValue = callback.call(T, kValue, k, O); // iii. Call the DefineOwnProperty internal method of A with arguments // Pk, Property Descriptor // { Value: mappedValue, // Writable: true, // Enumerable: true, // Configurable: true }, // and false. // In browsers that support Object.defineProperty, use the following: // Object.defineProperty(A, k, { // value: mappedValue, // writable: true, // enumerable: true, // configurable: true // }); // For best browser support, use the following: A[k] = mappedValue; } // d. Increase k by 1. k++; } // 9. return A return A; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (fun /*, thisArg */ ) { "use strict"; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (typeof fun !== "function") throw new TypeError(); var res = []; var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t) { var val = t[i]; if (fun.call(thisArg, val, i, t)) res.push(val); } } return res; }; } if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 internal IsCallable 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 && oThis ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; } if (!Array.indexOf) { Array.prototype.indexOf = function (obj) { for (var i = 0; i < this.length; i++) { if (this[i] == obj) { return i; } } return -1; } } // Object.keys if (!Object.keys) { Object.keys = (function () { 'use strict'; // modified from https://github.com/es-shims/object-keys var has = Object.prototype.hasOwnProperty; var toStr = Object.prototype.toString; var isEnumerable = Object.prototype.propertyIsEnumerable; var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); var dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ]; var equalsConstructorPrototype = function (o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; var excludedKeys = { $console: true, $external: true, $frame: true, $frameElement: true, $frames: true, $innerHeight: true, $innerWidth: true, $outerHeight: true, $outerWidth: true, $pageXOffset: true, $pageYOffset: true, $parent: true, $scrollLeft: true, $scrollTop: true, $scrollX: true, $scrollY: true, $self: true, $webkitIndexedDB: true, $webkitStorageInfo: true, $window: true }; var hasAutomationEqualityBug = (function () { /* global window */ if (typeof window === 'undefined') { return false; } for (var k in window) { try { if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { try { equalsConstructorPrototype(window[k]); } catch (e) { return true; } } } catch (e) { return true; } } return false; }()); var equalsConstructorPrototypeIfNotBuggy = function (o) { /* global window */ if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(o); } try { return equalsConstructorPrototype(o); } catch (e) { return false; } }; function isArgumentsObject(value) { var str = toStr.call(value); var isArgs = str === '[object Arguments]'; if (!isArgs) { isArgs = str !== '[object Array]' && value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && toStr.call(value.callee) === '[object Function]'; } return isArgs; }; return function keys(object) { var isFunction = toStr.call(object) === '[object Function]'; var isArguments = isArgumentsObject(object); var isString = toStr.call(object) === '[object String]'; var theKeys = []; if (object === undefined || object === null) { throw new TypeError('Cannot convert undefined or null to object'); } var skipProto = hasProtoEnumBug && isFunction; if (isString && object.length > 0 && !has.call(object, 0)) { for (var i = 0; i < object.length; ++i) { theKeys.push(String(i)); } } if (isArguments && object.length > 0) { for (var j = 0; j < object.length; ++j) { theKeys.push(String(j)); } } else { for (var name in object) { if (!(skipProto && name === 'prototype') && has.call(object, name)) { theKeys.push(String(name)); } } } if (hasDontEnumBug) { var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var k = 0; k < dontEnums.length; ++k) { if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { theKeys.push(dontEnums[k]); } } } return theKeys; }; }()); } //为IE浏览器补丁end=============================== //其余的扩展here //如果还没有扩展这个语言级工具类,则扩展之 if (!Date.prototype.format) { //对Date的扩展,将 Date 转化为指定格式的String //月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, //年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) //例子: //(new Date()).format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 //(new Date()).format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 Date.prototype.format = function (fmt) { // author: meizz var o = { "M+": this.getMonth() + 1, // 月份 "d+": this.getDate(), // 日 "h+": this.getHours(), // 小时 "m+": this.getMinutes(), // 分 "s+": this.getSeconds(), // 秒 "q+": Math.floor((this.getMonth() + 3) / 3), // 季度 "S": this.getMilliseconds() // 毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "") .substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; }; } } //TODO: 其它语言扩展可添加于此 }, //构造函数表 _classes: { /** * 发布、订阅模式的工厂类<br> * 如果想用,请实例化,例如:var pubSub = new NS.PubSub();<br> * 绑定事件的方法:bind(eventType, handler)、on(eventType, handler)<br> * 解除事件的方法:clear(eventType, handler)、off(eventType, * handler),可以解除绑定某个事件,也可以解除绑定所有事件<br> * 查看已绑事件列表:show(eventType)、view(eventType)<br> * 手动触发某个事件:fire(eventType)、trigger(eventType)、emit(eventType)<br> * 重置该对象,移出所有绑定的事件; reset() */ PubSub: function () { //是否开启日志 this.debugMode = true; /** * 事件处理器列表 * 结构如下: * click:[functionA, functionB, functionC, ...] * blur:[functionD, functionE, functionF, ...] * ... */ this.handlers = {}; /** * 为某种事件名成绑定(追加)一个新的事件监听器<br> * 例如,PubSub.on("click",function(){ doSth...}) */ this.bind = this.on = function (eventType, handler) { if (!(eventType in this.handlers)) { // 若还从未绑定过此种事件类型,例如click事件 this.handlers[eventType] = []; // 为该种类的事件类型初始化一个空的处理器数组 } // 此时,this.handlers[eventType]可能是一个空数组,也可能是一个已经有了若干个处理器的数组了! this.handlers[eventType].push(handler); if (this.debugMode) { console.log("成功绑定" + eventType + "事件!"); } // 返回this,便于后续的继续的链式调用 return this; }; /** * 移除事件处理器 */ this.clear = this.off = function (eventType, handler) { if (eventType) { //对指定的事件类型进行移除 if (handler) { // 如果传参了,那么只移除指定的handler this.handlers[eventType].pop(handler); if (this.debugMode) { console.log("成功解除指定参数类型的" + eventType + "事件!"); } } else { // 移除所有的handler this.handlers[eventType] = []; if (this.debugMode) { console.log("成功解除所有的" + eventType + "事件!"); } } } else { //移除所有的事件类型 for (var et in this.handlers) { if (typeof (et) == "function") { //是一个function,不可以删除 } else if (typeof (et) == "string") { //可以删除 delete this.handlers[et]; } } } return this; }; /** * 打印所有的事件列表 */ this.show = this.view = function (eventType) { if (eventType) { if (this.handlers[eventType]) { console.log("当前绑定" + eventType + "类型的事件回调函数列表为:\n" + this.handlers[eventType]); } } else { for (var p in this.handlers) { if (typeof (p) == "string") { console.log("当前绑定" + p + "类型的事件回调函数列表为:\n" + this.handlers[p]); } } } return this; }; /** * 手工触发某个事件<br> * 例如:PubSub.emit("click","param1","param2");<br> * 那么,就会将PubSub对象上面绑定的所有的click事件函数依次触发(调用)一遍 */ this.fire = this.trigger = this.emit = function (eventType) { // 从第一个参数往后截取所有的后续参数的数组,例如,此例中,就是["param1","param2"] var handlerArgs = Array.prototype.slice.call(arguments, 1); if (this.handlers[eventType] && this.handlers[eventType].length > 0) { for (var i = 0; i < this.handlers[eventType].length; i++) { // this.handlers[eventType][i]就是那个绑定的函数,调用该函数,并传入参数,即可 this.handlers[eventType][i].apply(this, handlerArgs); } } else { if (this.debugMode) { console.log("未绑定任何 【" + eventType + "】 事件!忽略调用!"); } } // 返回this,便于后续的继续的链式调用 return this; }; /** * 重置整个对象,清除其上面绑定的所有的事件<br> * 该方法用于重新使用该对象 */ this.reset = function () { this.handlers = {}; console.log("对象已重置,绑定的事件已被清空!"); } } //TODO: 其它构造函数可添加于此 } }; //让JS扩展即刻生效 NS._ext.jsLangExt(); //调用构造函数 //创建一个开箱即用的发布订阅模式的实例 NS.PB = new NS._classes.PubSub(); window.NS = NS; }(window));