let mm = { /** * 判断各种对象类型是否相等 * @param a [比较方a] * @param b [比较方b] * @returns {boolean} */ isEqual(a, b) { //如果a和b本来就全等 if (a === b) { //判断是否为0和-0 return a !== 0 || 1 / a === 1 / b; } //判断是否为null和undefined if (a == null || b == null) { return a === b; } //接下来判断a和b的数据类型 let classNameA = toString.call(a), classNameB = toString.call(b); //如果数据类型不相等,则返回false if (classNameA !== classNameB) { return false; } //如果数据类型相等,再根据不同数据类型分别判断 switch (classNameA) { case '[object RegExp]': case '[object String]': //进行字符串转换比较 return '' + a === '' + b; case '[object Number]': //进行数字转换比较,判断是否为NaN if (+a !== +a) { return +b !== +b; } //判断是否为0或-0 return +a === 0 ? 1 / +a === 1 / b : +a === +b; case '[object Date]': case '[object Boolean]': return +a === +b; } //如果是对象类型 if (classNameA == '[object Object]') { //获取a和b的属性长度 let propsA = Object.getOwnPropertyNames(a), propsB = Object.getOwnPropertyNames(b); if (propsA.length != propsB.length) { return false; } for (let i = 0; i < propsA.length; i++) { let propName = propsA[i]; //如果对应属性对应值不相等,则返回false if (a[propName] !== b[propName]) { return false; } } return true; } //如果是数组类型 if (classNameA == '[object Array]') { if (a.toString() == b.toString()) { return true; } return false; } }, /** * 对象深拷贝 * @param data * @returns {any} */ objDeepCopy(data) { return JSON.parse(JSON.stringify(data)); }, copyProperties :function(target,source){ for(let key of Reflect.ownKeys(source)){ if(key!=='constructor'&&key!=='prototype'&&key!=='name'){ let desc=Object.getOwnPropertyDescriptor(source,key); Object.defineProperty(target,key,desc); } } }, /** * 多重继承, 可以用建造者模式去设计程序 * @param {classA, classB, classC} mixins * @returns {Mix} * 使用指南 * // 定义A * class A { init_A(){ this.dream_A = '轮子滚动了'; this.leg_A = 'leg'; return this; } roll_A(){ console.log(this.dream_A); return this; } } // 定义B class B { init_B(){ this.dream_B = 'dreamB'; return this; } doSth_B() { console.log(this.dream_B); } } // 定义类并多重继承 class D extends mm.mix(A,B) { } // 组装 let car = new D().init_A().init_B(); // 调用 car.roll_A(); car.doSth_B(); */ mix: function(...mixins){ class Mix{} for(let mixin of mixins){ this.copyProperties(Mix,mixin); this.copyProperties(Mix.prototype,mixin.prototype); } return Mix }, /** * // Match反复匹配 * @param str [要匹配的字符串] * @param reg [匹配的正则] * @returns {arry} */ matchAll(str, reg) { let result = []; if (reg.flags.indexOf('g') === -1) { console.error('ERROR: 正则中请加入全局修饰符g'); return; } let match; let n = 0; while (match = reg.exec(str)) { result.push(match); } return result; }, /** * 得到浏览器query参数 * @param name * @returns {any} */ getUrlParam: function (name) { // 例如检索出 happymmall.com/product/list?keyword=xxx&page=1 每个参数值 let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); // window.location.search 就是 ?keyword=xxx&page=1这段参数 let result = window.location.search.substr(1).match(reg); // 如果有值进行解码 return result ? decodeURIComponent(result[2]) : null; }, // 增加一些选择器 setSelectMethod() { /** * 选择兄弟元素, 同jq的siblings * @param callback * @returns {Array} */ Element.prototype.siblings = function (callback) { let siblingElement = []; let parentAllElement = []; if (!this.parentNode) { return siblingElement; } // 限定在元素下 parentAllElement = this.parentNode.getElementsByTagName(this.tagName); for (let i = 0, iLen = parentAllElement.length; i < iLen; i++) { if (parentAllElement[i] != this) { siblingElement.push(parentAllElement[i]); typeof callback == "function" && callback.call(parentAllElement[i]); } } return siblingElement; }; }, /** * 增加一些个人方法 */ setMethod() { /** * 给数组元素批量 * @param {string} className [要添加的类名] * @returns {Array} 用来链式调用 */ Array.prototype.addClass = function (className) { let len = this.length; for (let i = 0, iLen = this.length; i < iLen; i++) { this[i].classList.add(className); } return this; }; /** * 数组批量移除类名 * @param className * @returns {Array} */ Array.prototype.removeClass = function (className) { let len = this.length; for (let i = 0, iLen = this.length; i < iLen; i++) { this[i].classList.remove(className); } return this; }; /** * 批量切换类的有无 * @param className * @returns {Array} */ Array.prototype.toggleClass = function (className) { let len = this.length; for (let i = 0, iLen = this.length; i < iLen; i++) { this[i].classList.toggle(className); } return this; }; /** * 添加类 * @param className * @returns {Element} */ Element.prototype.addClass = function (className) { this.classList.add(className); return this; }; /** * 移除某个类 * @param className * @returns {Element} */ Element.prototype.removeCLass = function (className) { this.classList.remove(className); return this; }; /** * 切换类的有无 * @param className * @returns {Element} */ Element.prototype.toggleClass = function (className) { this.classList.toggle(className); return this; }; /** * 判断是否包含某个类 * @param className * @returns {boolean} */ Element.prototype.hasClass = function (className) { return this.classList.contains(className); }; /** * 去除所有空格 * @returns {string} */ String.prototype.trimAll = function () { return this.replace(/\s*/g, '') }; /** * 编码html字符串, 防止XSS攻击 * @returns {string} */ String.prototype.escapeHTML = function () { return this.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); }; /** * 解码html字符串 * @returns {string} */ String.prototype.unEscapeHTML = function () { return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, '').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); }; /** * 得到数据类型名(开头字母大写) 如[] -> Array * 使用: let a = [] a.getType() * @returns {string} */ Object.prototype.getType = function () { return toString.call(this).match(/^\[object\s(\w*)(\])$/)[1]; }; } }; export default mm;