js 笔记整理
Js中for、for-in、forEach以及for-of的用法及特性对比
for-in
for...in以任意顺序遍历一个对象的可枚举属性。所以for-in不适合用来迭代一个Array。同时,for-in是可以遍历对象中所有可枚举属性的,包括原型链上的可枚举属性。
let ret = []; array.num = 6; // 对象上直接添加属性 Array.prototype.num = 6; // 原型链中添加属性 for(let i in array){ ret.push(array[i]) } console.log(ret) // [ 1, 2, 3, 4, 5, 6, 7 ]
如果可以地设置属性为不可枚举,那么for-in循环将不会遍历到这个属性
let ret = []; Object.defineProperty(array,"num",{ enumerable: false, // 设置属性不可遍历 value: 8 }) for(let i in array){ ret.push(array[i]) } console.log(ret) // [ 1, 2, 3, 4, 5 ]
解决方法:使用hasOwnProperty()
hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中。这个方法只在给定属性存在于对象实例中时,才会返回true。
/数组 var arr = ["星期一","星期二","星期三"]; Array.prototype.something = ["放假","休息咯"]; for (var i in arr){ if(arr.hasOwnProperty(i)){ console.log(arr[i]) } }
for(最原始的写法)、 支持 break、continue和return语句)、
forEach 数组的方法,arr.forEach; forEach(ES5,但是它不支持使用break、continue和return语句)、
for…in循环数组索引、对象的属性,但使用 for…in 原型链上的所有属性都将被访问,用 hasOwnProperty() 方法解决。
for…of(ES6,循环数组的元素值)这三个是循环数组(对象数组)的;
定义变量的6种方式
ES5 只有两种声明变量的方法:
var
命令和function
命令。
ES6 除了添加let
和const
命令,
还有 import
命令和class
命令。
去重两种方式
方法一 分析
function unique(arr) { //定义常量 res,值为一个Map对象实例 const res = new Map(); //返回arr数组过滤后的结果,结果为一个数组 //过滤条件是,如果res中没有某个键,就设置这个键的值为1 return arr.filter((a) => !res.has(a) && res.set(a, 1)) }
方法二:
function unique(arr) { return Array.from(new Set(arr)) }
两种还是有差异的,比如[2,,3,3]==>[2,3]/[2,3,undefined]
-----------------------
不指定字段去 es6 new Set 有缺陷,无法过滤 null,undefined
function myseta(ary) { const strings = ary.map((item) => JSON.stringify(item)) // 使用Set数据结构去重对象 // return new Set(strings) //var arr6 = [null, "null", undefined, "undefined", "", NaN, null, , undefined, , , NaN, ""] //console.log("strings", strings) // ['null', '"null"', undefined, '"undefined"', '""', 'null', undefined] // 使用Array.from()把Set数据结构去重对象后的结构,转为数组 // return Array.from(new Set(strings)) //报错 JSON.parse(item) "undefined" is not valid JSON // 使用Array.from()转为数组,然后再使用数组的map方法把数组里面的字符串类型转化为对象类型: return Array.from(new Set(strings)).map((item) => JSON.parse(item)) };
特别注意下面可,完美 过滤null,NaN,undefined,{}
function normalarr(array, index) { // var arr5 =[1, 2, 0, 0, null, "null", false, "false", {"id": 1}, {"id": 2}, {"id": 1},5, "5", {}, {}] // var arr6 = [null, "null", undefined, "undefined", "", NaN, null, , undefined, , , NaN, ""] // var arr7 = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, // 'NaN', 0, 0, 'a', 'a', {}, {} // ] //console.log("去重arr5 ", unique(arr5)) //[[1, 2, 0, null, 'null', false, 'false', {id: 1}, {id: 2}, 5, '5', {}]] //console.log("去重arr6 ", unique(arr6)) //[null, 'null', undefined, 'undefined', '', NaN] //console.log("去重arr7 ", unique(arr7)) //[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {}] var obj = {}; return array.filter(function(item, index) { //console.log("typeof item + item", typeof item + JSON.stringify(item)) var hasOne = typeof item + JSON.stringify(item) return obj.hasOwnProperty(hasOne) ? 0 : (obj[hasOne] = 1) //已存在则过滤,不然就新增属性 }) }
字段去重 指定与不指定 两者封装
function unique(array, prop) { var len = array && array.length; if (!len) { return []; } var util = { isObject: function(value) { return Object.prototype.toString.call(value) === '[object Object]'; } } function normalarr(array, index) { // var arr5 =[1, 2, 0, 0, null, "null", false, "false", {"id": 1}, {"id": 2}, {"id": 1},5, "5", {}, {}] // var arr6 = [null, "null", undefined, "undefined", "", NaN, null, , undefined, , , NaN, ""] // var arr7 = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, // 'NaN', 0, 0, 'a', 'a', {}, {} // ] //console.log("去重arr5 ", unique(arr5)) //[[1, 2, 0, null, 'null', false, 'false', {id: 1}, {id: 2}, 5, '5', {}]] //console.log("去重arr6 ", unique(arr6)) //[null, 'null', undefined, 'undefined', '', NaN] //console.log("去重arr7 ", unique(arr7)) //[1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {}] var obj = {}; return array.filter(function(item, index) { //console.log("typeof item + item", typeof item + JSON.stringify(item)) var hasOne = typeof item + JSON.stringify(item) return obj.hasOwnProperty(hasOne) ? 0 : (obj[hasOne] = 1) //已存在则过滤,不然就新增属性 }) } function uuidarr(array, prop) { // var ary1 = [ // {id: 0,text: 0}, // {id: 1,text: "1"}, // {id: 1,text: "1"}, // {id: 2,text: "2"}, // {id: '',text: ''}, // {id: true,text: true}, // {id: null,text: null}, // {id: NaN,text: NaN}, // {id: undefined,text: undefined}, // {id: "true",text: "true"}, // {id: "null",text: null}, // {id: "NaN",text: NaN}, // {id: "undefined",text: undefined}, // ]; var result = []; var obj = {}; var len = array.length; for (var i = 0; i < len; i++) { var oneitem = array[i]; if (util.isObject(oneitem) && oneitem.hasOwnProperty(prop)) { var oneVal = oneitem[prop]; //区分 字符串 [null,NaN, undefined,"null","NaN","undefined"] //var keyOne =oneVal;无法区分字符串 null 与 "null" NaN 与 "NaN" undefined 与 "undefined" var keyOne = typeof oneVal + oneVal; if (!obj[keyOne]) { result.push(oneitem); obj[keyOne] = 1; } } } return result; } if (typeof prop === "undefined") { return normalarr(array) } return uuidarr(array, prop) }
数组中存在某个字段
function inArray(elem, array, i) { var util = { isNaN: function(value) { return value !== value }, isObject: function(value) { return Object.prototype.toString.call(value) === '[object Object]'; }, } // var array = []; arr[2] = 1; // var array = [null, '', NaN, undefined, {}, "null", "undefined", "NaN", "{}", {id: 1}, {id: 2}, {id: 1}] // console.log(" null inArray", inArray(null, array)) // console.log(" '' inArray", inArray('', array)) // console.log(" NaN inArray", inArray(NaN, array)) // console.log(" undefined inArray", inArray(undefined, array)) // console.log(" {} inArray", inArray({}, array)) // console.log("'null' inArray", inArray('null', array)) // console.log("'undefined' inArray", inArray("undefined", array)) // console.log("'NaN' inArray", inArray('NaN', array)) // console.log("'{}' inArray", inArray('{}', array)) // console.log(" {id:1} inArray", inArray({ // id: 1, // }, array)) // console.log(" {id:2} inArray", inArray({ // id: 2, // }, array)) // console.log("'test' inArray", inArray("test", array)) var len = array && array.length; var i = i ? i < 0 ? Math.max(0, len + i) : i : 0; // 当i为负数时,从数组后边len+i的位置开始索引;当i不存在时,从数组首元素开始检索; if (!len) { return -1; } // console.log("i", i) if (!util.isNaN(elem) && !util.isObject(elem) && typeof elem !== 'undefined' && array.indexOf) { //console.log("indexOf") //1,array.indexOf 无法区分 NaN、{} ;2,array.indexOf(empty)返回-1 //var arr0 = [];arr0[2] = 1; 此时 arr0 =[empty × 2, 1] array.indexOf(arr0[0]) 查找为-1 return array.indexOf(elem) } for (; i < len; i++) { var oneitem = array[i]; //console.log(oneitem, "i in arr", i in array) if (util.isNaN(elem)) { if (util.isNaN(elem) === util.isNaN(oneitem)) { //console.log("isNaN", i) return i; } } else if (util.isObject(elem)) { if (JSON.stringify(elem) === JSON.stringify(oneitem)) { //console.log("obj", i) return i; } } else if (elem === oneitem) { //console.log("其他", i) return i; } } //没有找到的话就返回-1 return -1; }
数组去交集
// 原数组 const serveralArr = [ [1,2,2,5,3], [3,2,3,2,2], [3,2,4,4], [3], ] // 取交集 function intersectRepeat(arr){ var result= arr.reduce((a, b) => a.filter(c => b.includes(c))) // [4] result= Array.from(new Set(result)) return result } console.log("交集结果 是:",intersectRepeat(serveralArr)) // [2, 3]
变量作用域常见问题
//例如,以下代码会输出5次,结果都是5,那么如何输出0、1、2、3、4? for(var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 1000); } //利用闭包的原理实现,代码如下: for(var i = 0; i < 5; i++) { (function(e) { setTimeout(function() { console.log('传进来的是'+e); }, 1000); })(i); }
for(let i = 0; i < 5; i++) { setTimeout(function() { console.log('传进来的是'+i); }, 1000); }
数组中随机随 指定个数
function getRandomArray(arr,num){ //新建一个数组,将传入的数组复制过来,用于运算,而不要直接操作传入的数组; var temp_array = new Array(); for (var index in arr) { temp_array.push(arr[index]); } //取出的数值项,保存在此数组 var return_array = new Array(); for (var i = 0; i<num; i++) { //判断如果数组还有可以取出的元素,以防下标越界 if (temp_array.length>0) { //在数组中产生一个随机索引 var arrIndex = Math.floor(Math.random()*temp_array.length); //将此随机索引的对应的数组元素值复制出来 return_array[i] = temp_array[arrIndex]; //然后删掉此索引的数组元素,这时候temp_array变为新的数组 temp_array.splice(arrIndex, 1); } else { //数组中数据项取完后,退出循环,比如数组本来只有10项,但要求取出20项. break; } } return return_array; }
es6 字符串
$("#result").append( `He is <b>${person.name}</b>and we wish to know his${person.age}.that is all` );
:prop="`list.${index2}.tableData.${scope.$index}.input`"
js 数据类型判断 iview
function typeOf(obj) { const toString = Object.prototype.toString; const map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; return map[toString.call(obj)]; }
es6 剩余参数
function setData(index,howmany){ var arg=arguments; var index=arg[0]; var howmany=arg[1]; var newList =[].slice.call(arguments).filter(function (item,index) { return index>1; }); //var args = [].slice.call(arguments) // 避免泄露参数 参数是执行数组方法时括号中的参数 // http://jsperf.com/closure-with-arguments // let i = arguments.length // var args = new Array(i) // while (i--) { // args[i] = arguments[i] // } // 从第二个参数开始处理(数组下标1) // for (var i = 2, len = arguments.length; i < len; i++) { // result[arguments[i]] = object[arguments[i]] // } // 子类续承父类 //Rectangle.prototype = Object.create(Shape.prototype); //Rectangle.prototype.constructor = Rectangle; }
function func(a,b ...rest) { console.log(a) console.log(rest) } func(1) func(1, 2, 3, 4)
<script> function func(a) { var normalArray = [].slice.call(arguments); var default_len=arguments.callee.length; //获取形参的个数:函数名.length 或 arguments.callee.length var option_len=normalArray.length||0;//获取实参的个数:arguments.length console.log('arguments--------------',arguments,) console.log("default_len",default_len,"option_len",option_len,"normalArray",normalArray) var first=normalArray.slice(0,default_len); var rest=normalArray.slice((default_len)); if(default_len>=option_len){ rest=[]; console.log("相等",rest) } console.log("first",first) console.log("rest",rest) console.log("-------------------------------------------------------------------") } func() func(1) func(9,8) func(2, 6, 3, 4) </script>
// ES5 a = list[0], rest = list.slice(1) // ES6 [a, ...rest] = list
字符串长度
function length(str) { return [...str].length; } console.log( length('x\uD83D\uDE80y')) // 3 console.log( length('22')) // 2 console.log( length('哈哈')) // 2
伪数组转换为数组
var nodeList = document.querySelectorAll('div'); console.log([...nodeList]); // [div, div, div ... ]
拆解字符串与数组
var array = [1,2,3,4];
console.log(...array);//1 2 3 4
var str = "String";
console.log(...str);//S t r i n g
数组清空
数组中间 插入数组
<script> var arr1=[1,2,3,4,7,8] var arr2=[5,6] arr1.splice(4,0,...arr2) console.log("arr1",arr1) var adrr1=[1,2,3,4,7,8] var adrr2=[5,6] adrr1.splice.apply(adrr1,[4,0].concat(adrr2)) console.log("adrr1",adrr1) var array1=[1,2,3,4,7,8] var array2=[5,6] var nArray1 = array1.slice(0, 4).concat(array2, array1.slice(4)); var nArray2 = [...array1.slice(0, 4), ...array2, ...array1.slice(4)]; console.log("nArray1",nArray1) console.log("nArray2",nArray2) function insert(arrfirst,arrlast,index){ if (index < 0){ index = 0; }else if(index > arrfirst.length){ index = arrfirst.length; } for (var i = arrlast.length-1; i >= 0; i--){ arrfirst.splice(index,0,arrlast[i]);//是在index位置用arrlast[i]替换掉arrfirst数组中的0个元素 } return arrfirst; } var a1rr1=[1,2,3,4,7,8] var a1rr2=[5,6] console.log('insert',insert(a1rr1,a1rr2,4)); </script>
替换整个数组 splice 与slice
var ar2r=[1,2,3] var ar3r=[4,5,6] ar2r.splice(0,ar2r.length,...ar3r) var ar6r=ar3r.slice() console.log("ar2r",ar2r,'ar6r',ar6r,'ar3r',ar3r)//[4,5,6] // ar2r [4, 5, 6] ar6r (3) [4, 5, 6] ar3r (3) [4, 5, 6]
/** * Creates a slice of `array` from `start` up to, but not including, `end`. * * **Note:** This method is used instead of * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are * returned. * * @since 3.0.0 * @category Array * @param {Array} array The array to slice. * @param {number} [start=0] The start position. A negative index will be treated as an offset from the end. * @param {number} [end=array.length] The end position. A negative index will be treated as an offset from the end. * @returns {Array} Returns the slice of `array`. * @example * * var array = [1, 2, 3, 4] * * _.slice(array, 2) * // => [3, 4] */ function slice(array, start, end) { let length = array == null ? 0 : array.length; if (!length) { return []; } start = start == null ? 0 : start; end = end === undefined ? length : end; if (start < 0) { start = -start > length ? 0 : length + start; } end = end > length ? length : end; if (end < 0) { end += length; } length = start > end ? 0 : (end - start) >>> 0; start >>>= 0; let index = -1; const result = new Array(length); while (++index < length) { result[index] = array[index + start]; } return result; } export default slice;
start 是 {}
,却可以返回空数组而没有报错,秘诀在于使用了 >>>
, 这个符号叫做无符号右移操作符,>>>0
作用是保证值是有意义的正整数,若无意义则缺省为 0,这里 {}>>>0
会被转换为 0,因此不会报错。
去掉opt里面的 ‘undefined’,‘null ’ 字符串
Object.keys(opt).forEach(key => {
if (opt[key]&&(opt[key]=="undefined"||opt[key]=="null")) {
opt[key]="";
}
})
function deleteEmptyProp(opt,delArr,del) {
var delArr=delArr||["undefined","null",undefined,null,NaN];
for (var key in opt) {
var val=opt[key];
if (delArr.includes(val)) {
if(del){
delete opt[key];
}else{
var isValueNaN= (typeof val === 'number')&&(val !== val)?1:0;//判断NaN ,替换成0
if(isValueNaN){
opt[key]=0;
}else{
opt[key]="";
}
}
}
}
return opt;
}
var sas={a: 'duo1', b: 0, c: null,d:"null",e:"undefined",f:NaN,g:undefined}
console.log((deleteEmptyProp(sas)))
var sas2={a: 'duo2', b: 0, c: null,d:"null",e:"undefined",f:NaN,g:undefined,h:"NaN"}
console.log(deleteEmptyProp(sas2,["undefined","null","NaN"]))
限制数字两位小数或者正整数
<input class="uni-input" v-model="form1Data.aa" @input="handleInput($event,'aa',0)" placeholder="填写整数" /> <input class="uni-input" v-model="form1Data.bb" @input="handleInput($event,'bb',2)" placeholder="填写2位小数" /> <input class="uni-input" v-model="form1Data.cc" @input="handleInput($event,'cc','int')" placeholder="整数不设置min 空开始,1有效" /> <input class="uni-input" v-model="form1Data.dd" @input="handleInput($event,'dd','int',{min:0})" placeholder="整数设置 0开始 " /> <input class="uni-input" v-model="form1Data.ee" @input="handleInput($event,'ee','int',{min:1})" placeholder="整数设置 1开始" /> <input class="uni-input" v-model="form1Data.ff" @input="handleInput($event,'ff','int',{min:3,max:5})" placeholder="整数设置 3开始,最大5" />
使用
handleInput(e,prop,len,minAndMaxOut){ //正则表达试 var len=len||0; var val=e.detail&&e.detail.value||e.target&&e.target.value||e; if (val!="") { //console.log("handleInput "+prop,"--val--",val,typeof val) if(len==0||len=="int"||len=="integer"){ //console.log("正整数",val); var isObj= Object.prototype.toString.call(minAndMaxOut) === '[object Object]' if(isObj){ val =parseInt(val||0); var minAndMax={min:"",max:""}// minAndMax={...minAndMax,...minAndMaxOut} if(val!=""&&val<parseInt(minAndMax.min)){ val=minAndMax.min } if(val!=""&&val>parseInt(minAndMax.max)){ val=minAndMax.max } if(val==0&&val<minAndMax.min){ //console.log(val,"数字0 的处理") val=minAndMax.min } }else{ val =parseInt(val||0)||""; } }else{ //console.log("正小数",val); var value=val; if(typeof value!="string"){ value=value.toString(); } value =value.replace(/[^\d.]/g,""); //清除"数字"和"."以外的字符 value =value.replace(/^\./g,""); //验证第一个字符是数字 value =value.replace(/\.{2,}/g,"."); //只保留第一个, 清除多余的 value =value.replace(".","$#$").replace(/\./g,"").replace("$#$",".");//限制"10.5." 这种情况 value =value.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3'); //只能输入两个小数 if (value.indexOf(".") < 0 && value != "") { value = parseFloat(value); } val=value; } } //重新赋值给input this.$nextTick(() => { if(val !== val){//值是为NaN val=""; } this.formData[prop]= val // console.log("最后 val",val,"this.form1Data."+prop,this.form1Data[prop]); }) },
对象拷贝 浅一层深拷贝 es5的 Object.assign({},objNew) 与 es6的 {...{},...objNew} 一样
<script> var target0 = { name: '0带你飞' } var result0 = Object.assign(target0) result0.name = "0新名字" console.log("Object.assign =>(target) 覆盖 旧的target", target0, '新的', result0) //覆盖 旧的target {name: '0新名字'} 新的 {name: '0新名字'} var target1 = { name: '1带你飞' } var result1 = Object.assign({}, target1) result1.name = "1新名字" console.log(" Object.assign =>({}, target) 拷贝 旧的target", target1, '新的', result1) //拷贝 旧的target {name: '1带你飞'} 新的 {name: '1新名字'} console.log("---------------------------") let person1 = { key: { age: '旧1的' } } let res1 = Object.assign({}, person1) res1.key.age = "新1的" + 18 console.log("拷贝第2层浅拷贝 ", "旧", person1, "新", res1) //拷贝第2层浅拷贝 旧 {key: {age: '新1的18'} 新 {key: {age: '新1的18'} // 深拷贝 let person2 = { key: { name: '旧1的' } } let res2 = Object.assign({}, person2) res2.key = "新2的" + 28 console.log("拷贝第1层深拷贝 ", "旧", person2, "新", res2) //拷贝第1层深拷贝 旧 {key: {name: '旧1的'}} 新 {key: '新2的28'} var objnew11 = { name: "1旧的第一层" } var objnew22 = { name: "2旧的第一层" } var copy11 = Object.assign({}, objnew11) var copy22 = { ...{}, ...objnew22 } copy11.name = "新的第1层" copy22.name = "新的第2层" console.log("copy11=Object.assign({},objnew11)形式----objnew11", objnew11, "新的", copy11) //copy11=Object.assign({},objnew11)形式----objnew11 {name: '1旧的第一层'} 新的 {name: '新的第1层'} console.log("copy22={...{},...objnew22}形式 -----objnew22", objnew22, "新的", copy22) //copy22={...{},...objnew22}形式 -----objnew22 {name: '2旧的第一层'} 新的 {name: '新的第2层'} </script>
结果:
数组浅拷贝
const arr = [1,2,3]
const copyArr = [...arr]
var arr1 = [1,2,3] var arr2 = arr1.slice() // 方法一 // var arr2 = arr1.concat() //方法二 arr2.push(4) console.log('arr1:', arr1) // arr1: [1, 2, 3] console.log('arr2:', arr2) // arr1: [1, 2, 3, 4]
深拷贝
function deepClone1(obj) { return JSON.parse(JSON.stringify(obj)); } function deepClone(obj) { // if (obj === null) return obj //if ([null, undefined, NaN, false].includes(obj)) return obj; if (typeof obj == 'function') return new Function('return ' + obj.toString())() if (typeof obj != 'object') return obj if (obj instanceof RegExp) return new RegExp(obj) if (obj instanceof Date) return new Date(obj) // 运行到这里,基本上只存在数组和对象两种类型了 let newObj = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {}; for (let index in obj) { newObj[index] = deepClone(obj[index]); // 对子项进行递归复制 } return newObj; } // 深度克隆 function deepClone3(obj) { // 对常见的“非”值,直接返回原来值 if ([null, undefined, NaN, false].includes(obj)) return obj; if (typeof obj !== "object" && typeof obj !== 'function') { //原始类型直接返回 return obj; } var o = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {}; for (let i in obj) { if (obj.hasOwnProperty(i)) { o[i] = typeof obj[i] === "object" ? deepClone3(obj[i]) : obj[i]; } } return o; }
测试数据
let obj = { a: 1, arr: [1, 3, 5, 7, 9], c: { num: 100 }, fn: function() { console.log(1) }, date: new Date(), reg: /\.*/g, aa: null, bb: undefined, cc: NaN, dd: false } console.log("原始", (obj)) console.log("deepClone1", deepClone1(obj)) console.log("deepClone", deepClone(obj)) console.log("deepClone3", deepClone3(obj))
测试结果
合并对象
function myExtend() { var length = arguments.length; var target = arguments[0] || {}; if (typeof target!="object" && typeof target != "function") { target = {}; } if (length == 1) { target = this; i--; } for (var i = 1; i < length; i++) { var source = arguments[i]; for (var key in source) { // 使用for in会遍历数组所有的可枚举属性,包括原型。 if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }
简单合并对象
//var obj3= {...{},...obj1,...obj2 } //var obj3 =Object.assign({},obj1,obj2) //var obj3= myExtend({},obj1,obj2)
var person1 = { name: '小明', age: 18, sex: '男', } var hobby = { music: '伤感类歌曲', like: '吃饭、睡觉、打游戏', } var xiaoHong = { ...person1, ...{name: '小红',sex:'女'}, ...hobby } console.log(xiaoHong) // 输出:{name: "小红", age: 18, sex: "女", music: "伤感类歌曲", like: "吃饭、睡觉、打游戏"}
jquery 版本
function myExtend2() { function isArray(arr) { return Object.prototype.toString.call(arr) === '[object Array]'; } function isFunction(arr) { return Object.prototype.toString.call(arr) === '[object Function]'; } function isPlainObject(arr) { return Object.prototype.toString.call(arr) === '[object Object]'; } var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = true; if (typeof target === "boolean") { deep = target; target = arguments[1] || {}; i = 2; } if (typeof target !== "object" && !isFunction(target)) { target = {}; } if (length === i) { target = this; --i; } for (; i < length; i++) { if ((options = arguments[i]) != null) { for (name in options) { src = target[name]; copy = options[name]; if (target === copy) { continue; } if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { if (copyIsArray) { copyIsArray = false; clone = src && isArray(src) ? src : []; } else { clone = src && isPlainObject(src) ? src : {}; } target[name] = myExtend2(deep, clone, copy); } else if (copy !== undefined) { target[name] = copy; } } } } return target; } var obj1 = { a: 1, name: "张珊", title: { text: 'hello world', subtext: 'It/s my world.' } }; var obj2 = { a: 2, name: "李四", title: { subtext: 'Yes, your world.' } } //var obj3= {...{},...obj1,...obj2 } // Object.assign(目标对象,...源对象)可以有多个源对象 //var obj3 =Object.assign({},obj1,obj2) //var obj3= myExtend({},obj1,obj2) //console.log("$",$.version) //var obj3= $.extend(true,{},obj1,obj2) //var obj3= myExtend({},obj1,obj2) var obj3 = myExtend2({}, obj1, obj2) obj3.name = '王五' console.log("obj1", obj1); console.log("obj2", obj2); console.log("obj3", obj3, "title", obj3.title);
那async到底哪里简化了Promise
我们在写Promise操作的时候,经常会把Promise作为一个函数的返回值,如果函数很多,我们就要一直 return new Promise(...)
,这样非常麻烦,既然都要返回Promise,如果有简化操作,岂不是很香嘛?那解决办法就是async~
async function test() { return 123; } // 上面的代码相当于写成这样 function test() { return new Promise((resolve, reject) => { resolve(123); }) }
---
async function mayi() { return "1蚂蚁雅黑"; } async function test() { console.log(await mayi()); } test(); // 上下代码等效 function mayi() { return new Promise((resolve, reject) => { resolve("1蚂蚁雅黑") }) } function test() { return new Promise((resolve, reject) => { mayi().then(res => { console.log(res) }) }) } test();
fetch('http://localhost:8088/getInfo?name=clz') .then(async (res) => { const data = await res.text() console.log(data) console.log(typeof data) })
for /while 循环 省略
var cars=["BMW","Volvo","Saab","Ford"]; for (var i=cars.length;i--;) { console.log(cars[i] + "<br>"); } var cars0=["BMW0","Volvo0","Saab0","Ford0"]; for (var i=0;i<cars0.length;i++) { console.log(cars0[i] + "<br>"); } var cars=["BMW1","Volvo1","Saab1","Ford1"]; var i=0; for (;cars[i];) { console.log(cars[i] + "<br>"); i++; } var cars2=["BMW2","Volvo2","Saab2","Ford2"]; var i=0; while (cars2[i]) { console.log(cars2[i] + "<br>"); i++; } var cars3=["BMW3","Volvo3","Saab3","Ford3"]; var i=cars3.length; while (i--) { console.log(cars3[i] + "<br>"); }
获取css3 translate 属性
function getTransform(el) { //获取translate
var transform = window.getComputedStyle(el, null).getPropertyValue('-webkit-transform')|| window.getComputedStyle(el, null).getPropertyValue('transform');
var matrix = transform.match(/matrix(3d)?\((.+?)\)/);
var is3D = matrix && matrix[1];
if (matrix) {
matrix = matrix[2].split(",");
if (is3D === "3d")
matrix = matrix.slice(12, 15);
else {
matrix.push(0);
matrix = matrix.slice(4, 7);
}
} else {
matrix = [0, 0, 0];
}
var result = [
Number(matrix[0]),
Number(matrix[1]),
Number(matrix[2])
];
console.log("result",result)
return result;
}
json对象 还是json字符串
/**
* 是否json字符串
*/
function isJSONStr(value) {
if (typeof value == 'string') {
try {
var obj = JSON.parse(value);
if (typeof obj == 'object' && obj) {
return true;
} else {
return false;
}
} catch (e) {
return false;
}
}
return false;
}
//https://github.com/lodash/lodash
function isJSONObj(obj){
return typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length;
}
移动端 键盘事件
onCompositionStart以及onCompositionEnd
两个dom 是否相同
所谓相同,指的是两个节点引用的是同一个对象; 所谓相等,指的是两个节点是否是同一类型,具有相等的属性(nodeName,nodeValue。。。等等),还有相等的attributes,childNodes(相同的位置包含相同的值) 语法:
node1.isSameNode(node2) node1.isEqualNode(node2)
formatDate
function formatDate(date) { var d = new Date(date), month = '' + (d.getMonth() + 1), day = '' + d.getDate(), year = d.getFullYear(); if (month.length < 2) month = '0' + month; if (day.length < 2) day = '0' + day; return [year, month, day].join('-'); } console.log(formatDate('Sun May 13,2016'))
toFormatNumber
function toFormatNumber(event,itemprops,item,minVal){ var item2=item; var result= item2[itemprops]||""; result = result.toString().replace(/[^\d.]/g,""); //清除“数字”和“.”以外的字符 result = result.replace(/\.{2,}/g,"."); //只保留第一个. 清除多余的 result = result.replace(".","$#$").replace(/\./g,"").replace("$#$","."); result= result.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3');//只能输入两个小数 if(result.indexOf(".")< 0 && result !=""){//以上已经过滤,此处如果没有小数点,首位不能为类似于 01、02的金额 result= parseFloat(result); } if(minVal&&result<minVal){ result=minVal; } this.$set(item2,itemprops,result); };
数组字符串
var str2 = "0123456789";
console.log(str2.slice(4,7)); //----------"456"
var arrs=[0,1,2,3,4,5,6,7,8,9];
console.log(arrs.slice(4,7)); //----------"[4,5,6]"
var test = 'hello world';
console.log(test.slice(4,7)); //o w
console.log(test.substring(4,7)); //o w
console.log(test.substr(4,7)); //o world
//需要注意的地方就是:substring是以两个参数中较小一个作为起始位置,较大的参数作为结束位置。
console.log(test.substring(7,4))
变量 提升 作用域
var msg1='This is message 1'; var msg3='This is message 3'; function otherFunction() { msg2='This is message 2'; //不使用var关键字,-其实也是定义一个全局变量 var msg3='Message 3'; var ms4='Message 4'; alert(msg1); //This is message 1 (-函数内当然可以访问到外面定义的全局变量,再深的函数嵌套一样能正确获到这个全局变量,这是JavaScript闭包的其中一种体现) alert(msg3); //Message 3 (局部变量msg3) alert(window.msg3); //This is message 3 (-使用window前缀访问同名的全局变量msg3) alert(this.msg3); //This is message 3 (-因为otherFunction ()定义在一个全局的环境中,此时otherFunction ()的this也是指向window,所有你看到window. msg3是等于this. msg3的) } otherFunction(); //otherFunction-函数外面定义的msg1和里面定义的msg2依然是全局变量 alert(window.msg1); //-- This is message 1 alert(window.msg2); //-- This is message 2 alert(window.ms4); // -- underfind 外部不可以访问内部
new操作符创建对象
一般来说,new操作符创建对象可以分为四个步骤:
1. 创建一个空对象
2. 将所创建对象的__proto__属性值设成构造函数的prototype属性值
3. 执行构造函数中的代码,构造函数中的this指向该对象
4. 返回该对象(除非构造函数中返回一个对象)并且最后隐式的返回 this 。
用代码表示如下:
function Person(a, b) { this.name = a; this.age = b; } Person.prototype.show = function() { console.log(this.name, this.age); }; // var p = new Person('address', 10); var p = {}; p.__proto__ = Person.prototype; Person.call(p, 'address', 10); console.log(p);
封装一下 大致如此
function realizeNew () { //创建一个新对象 let obj = {}; //获得构造函数 let Con = [].shift.call(arguments); //链接到原型(给obj这个新生对象的原型指向它的构造函数的原型) obj.__proto__ = Con.prototype; //绑定this let result = Con.apply(obj,arguments); //确保new出来的是一个对象 return typeof result === "object" ? result : obj }
js错误类型
Error对象有两个最基本的属性:
name:错误名称
message:错误提示信息
除了Error对象,JavaScript还定义了其他6种错误,即存在Error的6个衍生对象
EvalError:执行代码时发生的错误
RangeError:当一个数值型变量或参数超出有效范围时发生的错误
ReferenceError:引用一个不存在的变量时发生的错误
SyntaxError:解析代码时发生的语法错误
TypeError:变量或参数的类型无效时发生的错误
URIError:向encodeURI() 或者 decodeURI() 传入无效参数时发生的错误
js 命名规范
s:表示字符串。例如:sName,sHtml; n:表示数字。例如:nPage,nTotal; b:表示逻辑。例如:bChecked,bHasLogin; a:表示数组。例如:aList,aGroup; r:表示正则表达式。例如:rDomain,rEmail; f:表示函数。例如:fGetHtml,fInit; o:表示以上未涉及到的其他对象,例如:oButton,oDate; g:表示全局变量,例如:gUserName,gLoginTime;
匿名函数写法
//五大类 //第一类 //最常见的一种 ( function(w) { alert(w.location.href+","+11); }(window)); [ function(w) { alert(w.location.href+","+11); }(window) ]; //第二类 ~ function(w) { alert(w.location.href+","+11); }(window); ! function(w) { alert(w.location.href+","+11); }(window); + function(w) { alert(w.location.href+","+11); }(window); - function(w) { alert(w.location.href+","+11); }(window); //第三类 delete function(w) { alert(w.location.href+","+11); }(window); typeof function(w) { alert(w.location.href+","+11); }(window); void function(w) { alert(w.location.href+","+11); }(window); new function(w) { alert(w.location.href+","+11); }(window); new function() { alert(window.location.href+","+11); }; //第四类 var f = function(w) { alert(w.location.href+","+11); }(window); //第五类 1, function() { alert(window.location.href+","+11); }(); 1 ^ function() { alert(window.location.href+","+11); }(); 1 > function() { alert(window.location.href+","+11); }(); 1 < function() { alert(window.location.href+","+11); }(); 1 / function() { alert(window.location.href+","+11); }(); 1 * function() { alert(window.location.href+","+11); }(); 1 | function() { alert(window.location.href+","+11); }(); 1 % function() { alert(window.location.href+","+11); }(); 1 & function() { alert(window.location.href+","+11); }();
获取元素尺寸
/** * Get element size * @param {HTMLElement} element * @returns {Object} {width, height} */ function getElementSize(element) { if (!element.getBoundingClientRect) { return { width: element.offsetWidth, height: element.offsetHeight } } var rect = element.getBoundingClientRect(); return { width: Math.round(rect.width), height: Math.round(rect.height) } }
dom 变化2
// http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ (function(){ var attachEvent = document.attachEvent; var isIE = navigator.userAgent.match(/Trident/); console.log(isIE); var requestFrame = (function(){ var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function(fn){ return window.setTimeout(fn, 20); }; return function(fn){ return raf(fn); }; })(); var cancelFrame = (function(){ var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.clearTimeout; return function(id){ return cancel(id); }; })(); function resizeListener(e){ var win = e.target || e.srcElement; if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__); win.__resizeRAF__ = requestFrame(function(){ var trigger = win.__resizeTrigger__; trigger.__resizeListeners__.forEach(function(fn){ fn.call(trigger, e); }); }); } function objectLoad(e){ this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; this.contentDocument.defaultView.addEventListener('resize', resizeListener); } window.addResizeListener = function(element, fn){ if (!element.__resizeListeners__) { element.__resizeListeners__ = []; if (attachEvent) { element.__resizeTrigger__ = element; element.attachEvent('onresize', resizeListener); } else { if (getComputedStyle(element).position == 'static') element.style.position = 'relative'; var obj = element.__resizeTrigger__ = document.createElement('object'); obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;'); obj.__resizeElement__ = element; obj.onload = objectLoad; obj.type = 'text/html'; if (isIE) element.appendChild(obj); obj.data = 'about:blank'; if (!isIE) element.appendChild(obj); } } element.__resizeListeners__.push(fn); }; window.removeResizeListener = function(element, fn){ element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); if (!element.__resizeListeners__.length) { if (attachEvent) element.detachEvent('onresize', resizeListener); else { element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener); element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__); } } } })(); // // var myElement = document.getElementById('my_element'), // myResizeFn = function(){ // /* do something on resize */ // }; // addResizeListener(myElement, myResizeFn); // removeResizeListener(myElement, myResizeFn);
--
function resizeObserver(ele,fn,self){ //MutationObserver、IntersectionObserver、ResizeObserver var dom=ele; var self=self||this;; // window.ResizeObserver=false; if(window.ResizeObserver){//resize-observer-polyfill var myObserver = new ResizeObserver(function(entries) { if(dom.tick){ clearTimeout(dom.tick) } dom.tick=setTimeout(function(){ entries.forEach(function(entry){ entry.offsetHeight=entry.borderBoxSize[0].blockSize||dom&&dom.offsetHeight; entry.offsetWidth=entry.borderBoxSize[0].inlineSize||dom&&dom.offsetWidth; //console.log("原生 ResizeObserver",entry,'version',self.version) fn&&fn.call(null,entry,self) }) },12) }) myObserver.observe(dom) }else{ // polyfill 兼容处理 addResizeListener(ele,function(e){ var entry={ offsetHeight:dom.offsetHeight, offsetWidth:dom.offsetWidt, }; // console.log("自定义 addResizeListener",entry,'version',self.version) fn&&fn.call(null,entry,self) }) } }
监听dom 变化
//ResizeSensor.js is part of a huge library, but I reduced its functionality to THIS: //https://stackoverflow.com/questions/6492683/how-to-detect-divs-dimension-changed/19418065#19418065 //var container = document.querySelector(".container"); // new ResizeSensor(container, function() // { // console.log("dimension changed:", container.clientWidth, container.clientHeight); // }); function ResizeSensor(element, callback) { var zIndex = parseInt(getComputedStyle(element)); if(isNaN(zIndex)) { zIndex = 0; }; zIndex--; var expand = document.createElement('div'); // expand.style.position = "absolute"; // expand.style.left = "0px"; // expand.style.top = "0px"; // expand.style.right = "0px"; // expand.style.bottom = "0px"; // expand.style.overflow = "hidden"; // expand.style.zIndex = zIndex; // expand.style.visibility = "hidden"; setStyle(expand,{ "position":"absolute", "left":"0px", "top":"0px", "right":"0px", "bottom":"0px", "overflow":"hidden", "zIndex":zIndex, "visibility":"hidden", }) var expandChild = document.createElement('div'); // expandChild.style.position = "absolute"; // expandChild.style.left = "0px"; // expandChild.style.top = "0px"; // expandChild.style.width = "10000000px"; // expandChild.style.height = "10000000px"; setStyle(expandChild,{ "position":"absolute", "left":"0px", "top":"0px", "width":"10000000px", "height":"10000000px", }) expand.appendChild(expandChild); var shrink = document.createElement('div'); // shrink.style.position = "absolute"; // shrink.style.left = "0px"; // shrink.style.top = "0px"; // shrink.style.right = "0px"; // shrink.style.bottom = "0px"; // shrink.style.overflow = "hidden"; // shrink.style.zIndex = zIndex; // shrink.style.visibility = "hidden"; setStyle(shrink,{ "position":"absolute", "left":"0px", "top":"0px", "right":"0px", "bottom":"0px", "overflow":"hidden", "zIndex":zIndex, "visibility":"hidden", }) var shrinkChild = document.createElement('div'); // shrinkChild.style.position = "absolute"; // shrinkChild.style.left = "0px"; // shrinkChild.style.top = "0px"; // shrinkChild.style.width = "200%"; // shrinkChild.style.height = "200%"; setStyle(shrinkChild,{ "position":"absolute", "left":"0px", "top":"0px", "width":"200%", "height":"200%", }) shrink.appendChild(shrinkChild); element.appendChild(expand); element.appendChild(shrink); function setScroll() { expand.scrollLeft = 10000000; expand.scrollTop = 10000000; shrink.scrollLeft = 10000000; shrink.scrollTop = 10000000; }; setScroll(); var size = element.getBoundingClientRect(); var currentWidth = size.width; var currentHeight = size.height; var onScroll = function() { var size = element.getBoundingClientRect(); var newWidth = size.width; var newHeight = size.height; if(newWidth != currentWidth || newHeight != currentHeight) { currentWidth = newWidth; currentHeight = newHeight; size.height=size.height||size.bottom - size.top||element.offsetHeight; size.width=size.width||size.right - size.left||element.offsetWidth; // console.log("element",element) // size.scrollTop=this.scrollTop; callback(size); } setScroll(); }; expand.addEventListener('scroll', onScroll); shrink.addEventListener('scroll', onScroll); function setStyle(eleObj, cssObj) { for (var property in cssObj) { eleObj.style[property] = cssObj[property]; }; } };
调用
function resizeObserver(ele,fn,self,timer){ //MutationObserver、IntersectionObserver、ResizeObserver var dom=ele; var self=self||this;; // window.ResizeObserver=false; if(window.ResizeObserver){//resize-observer-polyfill var myObserver = new ResizeObserver(function(entries) { if(dom.tick){ clearTimeout(dom.tick) } dom.tick=setTimeout(function(){ entries.forEach(function(entry){ // 这里的entry.target是DOM节点本身,而entry.contentRect是一个对象,包含了节点的位置属性,如width, height, left, right, bottom, left, x, y等。 // width:指元素本身的宽度,不包含padding,border值 // height:指元素本身的高度,不包含padding,border值 //offsetHeight = content + padding + border = 200 + 20 * 2 + 2 * 2 = 244 //clientHeight = content + padding = 200 + 20 * 2 = 240 entry.offsetHeight=entry.borderBoxSize[0].blockSize||dom&&dom.offsetHeight; entry.offsetWidth=entry.borderBoxSize[0].inlineSize||dom&&dom.offsetWidth; //console.log("原生 ResizeObserver",entry,'version',self.version) fn&&fn.call(null,entry,self) }) },timer||12) }) myObserver.observe(dom) }else{ // polyfill 兼容处理 if(ResizeSensor){ new ResizeSensor(dom, function(entry){ if(dom.tick){ clearTimeout(dom.tick) } dom.tick=setTimeout(function(){ entry.offsetHeight=entry.height||dom&&dom.offsetHeight;; entry.offsetWidth=entry.width||dom&&dom.offsetWidth; //console.log("我的 ResizeSensor",entry,'version',self.version) fn&&fn.call(null,entry,self) },timer||12) }); }else{ var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; if(MutationObserver){// ie var MutationObserverConfig={ childList: true, subtree: true, characterData: true }; var observer=new MutationObserver(function(entry){ if(dom.tick){ clearTimeout(dom.tick) } dom.tick=setTimeout(function(){ entry.offsetHeight=dom.offsetHeight; entry.offsetWidth=dom.offsetWidth; //console.log("ie MutationObserver",entry,'version',self.version) fn&&fn.call(null,entry,self) },timer||12) }); observer.observe(dom,MutationObserverConfig); }else{ // dom.addEventListener("DOMSubtreeModified",function(entry){ // if(dom.tick){ // clearTimeout(dom.tick) // } // dom.tick=setTimeout(function(){ // fn&&fn.call(null,entry,self) // },timer*8||100) // }, false); } } } }
---
var dom=document.querySelector(".scroll-height"); resizeObserver(dom,function(entry,self){ // console.log('2entry', entry) if(entry&&entry.offsetHeight){ var total= Math.ceil(entry.offsetHeight) ; self.maxScrollHeight=total-self.viewHeight; dom.setAttribute("scroll-height",self.maxScrollHeight) dom.setAttribute("max-total",total) self.setOneH() // console.log('检测 entry', entry) if(clickTop){ self.setTop(clickTop); } // console.log('clickTop',clickTop,'1有1 entry 检测dom 变化',self.maxScrollHeight) }else{ //ie var total=Math.ceil(dom.offsetHeight); self.maxScrollHeight=total-self.viewHeight; dom.setAttribute("scroll-height",self.maxScrollHeight) //ie 不可以设置 dom.setAttribute("max-total",total) self.setOneH() if(clickTop){ self.setTop(clickTop); } // console.log('clickTop',clickTop,'0无0 entry 检测dom 变化',self.maxScrollHeight) } },self);
//MutationObserver、IntersectionObserver、ResizeObserver
intersection-observer-polyfill
observe(target) {
if (!arguments.length) {
throw new TypeError('1 argument required, but only 0 present.');
}
if (!(target instanceof Element)) {
throw new TypeError('parameter 1 is not of type "Element".');
}
let targets = this._targets;
// Do nothing if target is already observed.
if (targets.has(target)) {
return;
}
// Create new IntersectionObservation instance and assign it
// to provided target.
targets.set(target, new IntersectionObservation(target, this));
// Connect current observer to controller
// if it wasn't connected yet.
if (!this.controller.isConnected(this)) {
this.controller.connect(this);
}
// Request the update of observers.
this.controller.startUpdateCycle();
}
elementui resize-event.js
import ResizeObserver from 'resize-observer-polyfill'; import { debounce } from 'throttle-debounce'; const isServer = typeof window === 'undefined'; /* istanbul ignore next */ const resizeHandler = function(entries) { for (let entry of entries) { const listeners = entry.target.__resizeListeners__ || []; if (listeners.length) { listeners.forEach(fn => { fn(); }); } } }; /* istanbul ignore next */ export const addResizeListener = function(element, fn) { if (isServer) return; if (!element.__resizeListeners__) { element.__resizeListeners__ = []; element.__ro__ = new ResizeObserver(debounce(16, resizeHandler)); element.__ro__.observe(element); } element.__resizeListeners__.push(fn); }; /* istanbul ignore next */ export const removeResizeListener = function(element, fn) { if (!element || !element.__resizeListeners__) return; element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); if (!element.__resizeListeners__.length) { element.__ro__.disconnect(); } };
使用
//先引入 import { addResizeListener, removeResizeListener } from 'utils/resize-event'; export default { mounted(){ //可以在mounted这个钩子里初始化事件 addResizeListener(this.$el, this.resizeListener); }, methods:{ resizeListener(){ //do something } }, //生命周期结束时销毁事件 destroyed() { if (this.resizeListener) removeResizeListener(this.$el, this.resizeListener); } }
空对象
const isEmpty = function(val) {
// null or undefined
if (val == null) return true;
if (typeof val === 'boolean') return false;
if (typeof val === 'number') return !val;
if (val instanceof Error) return val.message === '';
switch (Object.prototype.toString.call(val)) {
// String or Array
case '[object String]':
case '[object Array]':
return !val.length;
// Map or Set or File
case '[object File]':
case '[object Map]':
case '[object Set]': {
return !val.size;
}
// Plain Object
case '[object Object]': {
return !Object.keys(val).length;
}
}
return false;
};
数组 比较
//判断新旧数组 返回新数组相对老数组 增加数据 function returnAddData(oldArr, newArr) { var obj = {}; var index; //记录新数组中的索引 for (var i = 0; i < newArr.length; i++) { var sam= oldArr.some(function( item, index, array ){ return JSON.stringify(newArr[i]) === JSON.stringify(item) }) if (sam) { } else { index = i; } if (index !== undefined) obj[index] = newArr[index]; } return Object.values(obj); } //判断新旧数组 返回新数组相对老数组删除数据 function returnDeleteData(oldArr, newArr) { var obj = {}; var index; //记录老数组中的索引 for (var i = 0; i < oldArr.length; i++) { var sam=newArr.some( function( item, index, array ){ return JSON.stringify(oldArr[i]) === JSON.stringify(item); }) if (sam) { } else { index = i; } if (index !== undefined) obj[index] = oldArr[index]; } return Object.values(obj); }
js prop 与attr
- 对于HTML元素本身就带有的固有属性,在处理的时候,使用
prop()
方法。 prop 原生的,可以看成 dom 看成object 对象,通过 对象.属性 例如 获取id, element.id - 对于HTML元素我们自己自定义的DOM属性,在处理时,使用
attr()
方法。
其他。。。
uni-app
function mySystem() { var system=uni.getSystemInfoSync(); var statusBarHeight = system.statusBarHeight //状态栏高度 var navigatorHeight=44; var isAndroid=false; if(system.system.toLowerCase().indexOf("ios")!=-1) { navigatorHeight=44 isAndroid=false; }else { isAndroid=true; navigatorHeight=48 } var totalHeight=navigatorHeight+statusBarHeight //https://uniapp.dcloud.net.cn/tutorial/platform.html#preprocessor var platform=""; //#ifdef APP-PLUS platform = "APP-PLUS";///**App*/ //#endif //#ifdef APP-PLUS-NVUE || APP-NVUE platform = "APP-PLUS-NVUE";///**App nvue*/ //APP-PLUS-NVUE或APP-NVUE App nvue 页面 //#endif //#ifdef MP-WEIXIN platform = "MP-WEIXIN";///**微信小程序*/ //#endif var navInfo={ system:system, statusBarHeight:statusBarHeight, navigatorHeight:navigatorHeight, totalHeight:totalHeight, isAndroid:isAndroid, platform:platform, windowHeight:system.windowHeight, windowWidth:system.windowWidth, safeAreaInsetBottom:system.safeAreaInsets.bottom||0, } // localStorage&&localStorage.setItem("isAndroid", this.isAndroid) // localStorage&&localStorage.setItem("totalHeight", this.totalHeight) // localStorage&&localStorage.setItem("platform", platform) //console.log("mySystem ",navInfo,"platform",platform) return navInfo; }
function talkTormatTime(timestamp,all ) { if (!timestamp) { return } var date = new Date(timestamp) var strLen = timestamp.toString().length // 判断时间戳是否不足13位,不足时低位补0,即乘以10的所差位数次方 if (strLen < 13) { var sub = 13 - strLen sub = Math.pow(10, sub) // 计算10的n次方 date = new Date(timestamp * sub) } var nos = 1, bindf = '-'; var y = date.getFullYear() var M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 var d = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() var h = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() var m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds(); var todayStamp=+new Date; var today= new Date(todayStamp) if(today.getDate()==date.getDate()){//同一天 nos=-1; //console.log("同一天") if(date.getHours()==today.getHours()){//同一小时 //console.log("同一小时") var df=date.getMinutes() var tf=today.getMinutes() var sev=Math.abs(df-tf); //console.log("分差"+sev+"分钟",tf,df) if(sev<=3){//小于3分钟 刚刚 nos=-2; } } } var sa2=h + ':' + m //console.log("时间-分",sa2 ) if(all){ nos=0; } if(nos == -1){ return h + ':' + m ; } if(nos == -2){ return '刚刚' ; } //2022年4月22日 20:13 return y + "年" + M + "月" + d + '日' + ' ' + h + ':' + m ; }
----------------------------------------------------------------------
/** * @description 进行延时,以达到可以简写代码的目的 比如: await uni.$u.sleep(20)将会阻塞20ms * @param {number} value 堵塞时间 单位ms 毫秒 * @returns {Promise} 返回promise */ function sleep(ms) { return new Promise(function(resolve, reject) { setTimeout(resolve(true), ms|| 30) }) } // sleep(1000).then(() => { // console.log(2000) // }) /** * @desc 格式化手机号码 * @param {String} num 手机号码 **/ function numberFormatter(num) { return num.length === 11 ? num.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2') : num; } //-----------nvue------------------------------------------------------------------------ function getRect (id,vue,useUni,delay){ //ID选择器:#the-id #可以不要 紧紧支持id var that=vue;//Vue实例才拥有_isVue 属性,在此是避免观测Vue实例对象。 var id =id; if(!vue||!vue._isVue){ console.log("请传入vue 对象") //Promise.resolve(false); return false; } var useUni=useUni||false; var platform="APP-PLUS"; //#ifdef APP-PLUS-NVUE || APP-NVUE platform = "APP-NVUE";///**App nvue*/ //APP-PLUS-NVUE或APP-NVUE App nvue 页面 //#endif if(useUni){ platform="APP-PLUS"; } //console.log("getRect id",id) //console.log("getRect this",JSON.stringify(that)) if(platform=="APP-PLUS"){////nvue不支持 uni.createSelectorQuery, return new Promise(resolve => { setTimeout(() => { var selector=id.indexOf("#")!=-1?id:("#"+id); //console.log("selector ",selector) var query = uni.createSelectorQuery().in(that); query.select(selector).boundingClientRect(res => { res.methodType='uni'; resolve(res) //console.log("uni getRect 1得到布局位置信息" , res); //res={"id":"as2ss","dataset":{"ref":"as2ss"},"left":12,"right":312,"top":286,"bottom":336,"width":300,"height":50} }).exec(); }, delay||100); }) }else{ ////#ifdef APP-NVUE const dom = weex.requireModule('dom'); var id2=id.replace("#",'') //console.log("id2 ",id2) return new Promise(resolve => { setTimeout(() => { var talkcontent=that.$refs[id2] var result = dom.getComponentRect(talkcontent, res => { res.size.methodType='weex'; resolve(res.size) // console.log("weex getRect 2得到布局位置信息" , res); //res.size= {"right":300,"left":0,"width":300,"bottom":71,"top":21,"height":50} }) }, delay||100); }) //// #endif } } //<view id="as2ss" ref="as2ss" style="width: 300px; height: 50px; background-color:#666;"> 布局盒子</view> //async test_getRect(){ // var size=await getRect("#as2ss",this,"weex"); // console.log("getRect 结果--",size) // }, //-----------nvue------------------------------------------------------------------------ //https://github.com/umicro/uView/blob/master/uview-ui/libs/function/trim.js //trim.js function trim(str,pos ) { if(Object.prototype.toString.call(str) != "[object String]"){ return str; } var pos= pos||'botn' if (pos == "botn") {//两侧 return str.replace(/(^\s*)|(\s*$)/g,""); } if (pos == "left") { return str.replace(/^\s*/, ''); } if (pos == 'right') { return str.replace(/(\s*$)/g, ""); } //全部 return str.replace(/\s+/g, ""); } function typeOf(obj) { const toString = Object.prototype.toString; const map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; return map[toString.call(obj)]; } // "true" => true // "false" => false // "null" => null // "42" => 42 // "42.5" => 42.5 // "08" => "08" // JSON => parse if valid // String => self function deserializeValue(value) { var num try { return value ? value == "true" || ( value == "false" ? false : value == "null" ? null : !/^0/.test(value) && !isNaN(num = Number(value)) ? num : /^[\[\{]/.test(value) ? $.parseJSON(value) : value ) : value } catch(e) { return value } } // firstUpperCase function firstUpperCase(str) { return str.toString()[0].toUpperCase() + str.toString().slice(1); } function random(min, max) { if (min >= 0 && max > 0 && max >= min) { let gab = max - min + 1; return Math.floor(Math.random() * gab + min); } else { return 0; } } function unique(arr,prop){ if(!arr||!arr.length){ return []; } if(!prop){ return [...new Set(arr)]; } var result = []; var obj = {}; for (var i =0; i<arr.length; i++){ if (!obj[arr[i][prop]]){ result.push(arr[i]); obj[arr[i][prop]] = true; } } return result; } function getRandomArray(arr,num){ var temp_array = new Array(); for (var index in arr) { temp_array.push(arr[index]); } // console.log("1 getRandomArray arr",arr) //取出的数值项,保存在此数组 var return_array = new Array(); for (var i = 0; i<num; i++) { //判断如果数组还有可以取出的元素,以防下标越界 if (temp_array.length>0) { //在数组中产生一个随机索引 var arrIndex = Math.floor(Math.random()*temp_array.length); //将此随机索引的对应的数组元素值复制出来 return_array[i] = temp_array[arrIndex]; //然后删掉此索引的数组元素,这时候temp_array变为新的数组 temp_array.splice(arrIndex, 1); } else { //数组中数据项取完后,退出循环,比如数组本来只有10项,但要求取出20项. break; } } // console.log("getRandomArray",return_array) return return_array; } //------------is---------------------------------------------------------------------------- /** * 判断是否为空 */ function isEmpty(value) { switch (typeof value) { case 'undefined': return true; case 'string': if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true; break; case 'boolean': if (!value) return true; break; case 'number': if (0 === value || isNaN(value)) return true; break; case 'object': if (null === value || value.length === 0) return true; for (var i in value) { return false; } return true; } return false; } function isEmptyJSON(obj) { return !Object.getOwnPropertyNames(obj).length && !Object.getOwnPropertySymbols(obj).length||JSON.stringify(obj) === '{}' ; } function isHtmlElement(node) { return node && node.nodeType === Node.ELEMENT_NODE; } /** * 是否json字符串 */ function isJSONStr(value) { if (typeof value == 'string') { try { var obj = JSON.parse(value); if (typeof obj == 'object' && obj) { return true; } else { return false; } } catch (e) { return false; } } return false; } //https://github.com/lodash/lodash function isJSONObj(obj){ return typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length; } /** * 是否数组 */ function isArray(value) { if (typeof Array.isArray === "function") { return Array.isArray(value); } else { return Object.prototype.toString.call(value) === "[object Array]"; } } /** * 是否对象 */ function isObject(value) { return Object.prototype.toString.call(value) === '[object Object]'; } function isFunction(obj){ // console.log(isFunction(alert)); true // console.log(isFunction(console.log)); true // console.log(isFunction('GeeksgorGeeks')); false //https://github.com/jashkenas/underscore/blob/master/modules/isFunction.js //https://github.com/jashkenas/underscore/tree/master/modules //https://github.com/ElemeFE/element/blob/dev/src/utils/types.js var isFun = (obj) => { return obj && Object.prototype.toString.call(obj) === '[object Function]'; }; // Optimize `isFunction` if appropriate. Work around some `typeof` bugs in old // v8, IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). var nodelist =document&&document.childNodes; if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') { isFun = function(obj) { return typeof obj == 'function' || false; }; } return isFun(obj); } function isNumber(obj) { return obj === +obj } function isValueNaN(value) { return typeof value === 'number' && isNaN(value) } function isValueNaN2(value) { return value !== value } function isBoolean(obj) { return obj === !!obj } // -------正则 start------------------------------------------------------------------------------------- // https://github.com/validatorjs/validator.js var validator={ /** * 验证电子邮箱格式 */ email(value) { return /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/.test(value); }, /** * 验证手机格式 */ mobile(value) { return /^1[3-9]\d{9}$/.test(value) }, /** * 验证URL格式 */ url(value) { return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value) }, /** * 验证日期格式 */ date(value) { return !/Invalid|NaN/.test(new Date(value).toString()) }, /** * 验证十进制数字 */ number(value) { return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value) }, /** * 验证整数 */ digits(value) { return /^\d+$/.test(value) }, /** * 验证身份证号码 */ idCard(value) { return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value) }, /** * 金额,只允许2位小数 */ amount(value) { //金额,只允许保留两位小数 return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value); }, /** * 中文 */ chinese(value) { var reg = /^[\u4e00-\u9fa5]+$/gi; return reg.test(value); }, /** * 只能输入字母 */ letter(value) { return /^[a-zA-Z]*$/.test(value); }, /** * 只能是字母或者数字 */ enOrNum(value) { //英文或者数字 var reg = /^[0-9a-zA-Z]*$/g; return reg.test(value); }, /** * 验证一个值范围[min, max] */ range(value, param) { return value >= param[0] && value <= param[1] }, /** * 验证一个长度范围[min, max] */ rangeLength(value, param) { return value.length >= param[0] && value.length <= param[1] }, /** * 是否固定电话 */ landline(value) { var reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/; return reg.test(value); }, } // -------正则 end------------------------------------------------------------------------------------- //vue2 nextTick------------------------------------------------------------------ // 定义一个队列 const queue = []; function queueJob(job){ // 不存在队列中,则放入 if(!queue.includes(job)){ queue.push(job) } // 放入微队列中执行 nextTick2(() => { let jobFn // 取出队列中的第一个effect进行执行 while(jobFn = queue.shift()){ jobFn && jobFn() } }) } function nextTick2(fn){ return fn ? Promise.reslove.then(fn) : Promise.reslove() } function nextTick (cb, ctx) { var _resolve; // 放入回调函数,等待DOM重新渲染完毕后执行 callbacks.push(function () { if (cb) { try { // 修改执行上下文,指向当前页面实例 // 所以在我们没有使用箭头函数的前提下,this指向仍然正确 cb.call(ctx); } catch (e) { handleError(e, ctx, 'nextTick'); } } else if (_resolve) { _resolve(ctx); } }); if (!pending) { pending = true; timerFunc(); } // $flow-disable-line if (!cb && typeof Promise !== 'undefined') { return new Promise(function (resolve) { _resolve = resolve; }) } } // 原型链上,挂载此方法 // Vue.prototype.$nextTick = function (fn) { // //参数1:回调函数,参数二:页面实例执行上下文 // return nextTick(fn, this) // }; //timerFunc() //Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate, //如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。 //宏任务耗费的时间是大于微任务的,所以在浏览器支持的情况下,优先使用微任务。 //如果浏览器不支持微任务,使用宏任务;但是,各种宏任务之间也有效率的不同,需要根据浏览器的支持情况,使用不同的宏任务。 // const callbacks = [] // 回调队列 let pending = false // 异步锁 // 执行队列中的每一个回调 function flushCallbacks () { pending = false // 重置异步锁 // 防止出现nextTick中包含nextTick时出现问题,在执行回调函数队列前,提前复制备份并清空回调函数队列 const copies = callbacks.slice(0) callbacks.length = 0 // 执行回调函数队列 for (let i = 0; i < copies.length; i++) { copies[i]() } } let timerFunc; /* 优先检测微任务(micro task) */ // 检测浏览器是否原生支持 Promise if (typeof Promise !== 'undefined') { const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) } isUsingMicroTask = true } // 以上都不支持的情况下,使用setTimeout else { timerFunc = () => { setTimeout(flushCallbacks, 0) } } //vue3 nextTick------------------------------------------------------------------------- const resolvedPromise = Promise.resolve(); let currentFlushPromise = null; function nextTick(fn) { const p = currentFlushPromise || resolvedPromise; return fn ? p.then(this ? fn.bind(this) : fn) : p; } // ———————————————— // 版权声明:本文为CSDN博主「haruhiSzmy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 // 原文链接:https://blog.csdn.net/qq_42316310/article/details/125389053 //------------------------------------------------------------------------------ //https://github.com/view-design/ViewUIPlus/blob/master/src/utils/assist.js // download file export async function downloadFile(url, name = 'unnamed') { if (!isClient) return Promise.reject(); try { const res = await fetch(url); const blob = await res.blob(); if (!blob) return Promise.reject(); const localUrl = URL.createObjectURL(blob); const a = document.createElement('a'); a.setAttribute('href', localUrl); a.setAttribute('download', name); a.click(); URL.revokeObjectURL(localUrl); return Promise.resolve(); } catch(e) { return Promise.reject(e); } }
省市区 正则
var reg = /.+?(省|市|自治区|自治州|县|区)/g; var addressList = address.match(reg).toString().split(","); this.address.cityName = addressList[1];
table表格单元格的合并详解
/** * mergeCells 单元格合并处理 * @param text 当前单元格的值 * @param data 当前表格分页所有数据 * @param key 当前列的dataIndex * @param index 当前数据所在下标 * @param parentId 限定范围 [] * @returns {number} 待合并单元格数量 */ function mergeCells(text, data, key, index, parentId) { if (data.length < 1) { return 1; } if (text === '' || text === null) { data[index].rowNum = 1; return 1; } var spanArr = []; var pos = 0; for (var i = 0; i < data.length; i++) { if (i === 0) { spanArr.push(1); pos = 0; } else { if (parentId) { if (!Array.isArray(parentId)) { parentId = [parentId]; //console.log("parentId", parentId) } var canNext = true; for (var s = 0; s < parentId.length; s++) { var propOne = parentId[s]; if (data[i][propOne] !== data[i - 1][propOne]) { canNext = false; break; } } if (canNext && data[i][key] === data[i - 1][key]) { spanArr[pos] += 1; spanArr.push(0); } else { spanArr.push(1); pos = i; } } else { // 判断当前元素与上一个元素是否相同 if (data[i][key] === data[i - 1][key]) { spanArr[pos] += 1; spanArr.push(0); } else { spanArr.push(1); pos = i; } } } // console.log("spanArr", spanArr); } return data[index].rowNum = spanArr[index]; };
elementui table 使用方式
<el-table:data="treeMenu" :span-method="objectSpanMethod" >
objectSpanMethod({ row, column, rowIndex, columnIndex, }) { if (columnIndex == 2) { var prop = 'amount1' var value = row.name; var index = rowIndex; var rowspan = mergeCells(value, this.treeMenu, prop, index, ["vid", 'name']) // 获取需要合并的行数 // console.log(rowIndex, "name rows", rowspan) return { rowspan: rowspan ? rowspan : 0, colspan: rowspan ? 1 : 0 }; } }