js那些事儿(this指向,常用正则,数组操作...)

224 阅读9分钟

目录


跳转锚点平滑

// 跳转锚点 平滑
function goTarget(target) {
    var timer = null;
    var lastPos = 0;
    function goMove() {
        var currentPosition = document.documentElement.scrollTop || document.body.scrollTop;
        currentPosition = parseInt(currentPosition)
        if(lastPos == currentPosition) { //页面高度不够长,未滑动到指定位置的时候,已经滑动到底部了
            window.scrollTo(0, target);
            clearInterval(timer);
            console.log('move to ' + target);
            return;
        }
        lastPos = currentPosition;
        // console.log(target, currentPosition);
        if(Math.abs(currentPosition - target) < 20) {
            window.scrollTo(0, target);
            clearInterval(timer);
            return;
        }
        if (currentPosition -target > 20) {
            currentPosition -= 20;
            window.scrollTo(0, currentPosition);
        } else {
            currentPosition += 20;
            window.scrollTo(0, currentPosition);
        }
    }
    timer = setInterval(goMove, 10);
}

监听input输入完成时

var cpLock = true;
$('.textrareas').on('compositionstart', function () { //输入中
    cpLock = false;
});
$('.textrareas').on('compositionend', function () {//输入结束
    cpLock = true;
})

检测当前运行环境

var u = navigator.userAgent, app = navigator.appVersion;
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //g
var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if(isIOS){
    
}
if(isAndroid){
    
}
function IsPC() { // pc检测
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone",
            "SymbianOS", "Windows Phone",
            "iPad", "iPod"];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
    if (userAgentInfo.indexOf(Agents[v]) > 0) {
        flag = false;
        break;
    }
}
return flag;
}

function isWeiXin(){ // 微信环境
    var ua = window.navigator.userAgent.toLowerCase(); 
    if(ua.match(/MicroMessenger/i) == 'micromessenger'){ 
        return true; 
    }else{ 
        return false; 
    }
} 

时间戳转日期

/**
 * 时间戳转换日期
 * @param <int> unixTime    待时间戳(秒)
 * @param <bool> isFull    返回完整时间(Y-m-d 或者 Y-m-d H:i:s)
 * @param <int>  timeZone   时区
 */
var UnixToDate = function (unixTime, isFull, timeZone) {
    if (typeof (timeZone) == 'number'){
        unixTime = parseInt(unixTime) + parseInt(timeZone) * 60 * 60;
    }
    var time = new Date(unixTime * 1000);
    var ymdhis = "";
    ymdhis += time.getUTCFullYear() + "-";
    ymdhis += ((time.getMonth()+1) >= 10 ? time.getMonth()+1 : '0'+(time.getMonth()+1)) + "-";
    ymdhis += time.getDate() >= 10 ? time.getDate() : '0'+time.getDate();
    if (isFull === true){
        ymdhis += " " + (time.getHours() >=10 ? time.getHours() : '0'+time.getHours()) + ":";
        ymdhis += (time.getMinutes() >=10 ? time.getMinutes() : '0'+time.getMinutes())+ ":";
        ymdhis += (time.getSeconds() >= 10 ? time.getSeconds() : '0'+time.getSeconds());
    }
    return ymdhis;
}

检测变量类型

Object.prototype.toString.call(result);// 检测变量类型
判断数组类型 var arr=[]; arr instanceof Array;

JavaScript 深拷贝 浅拷贝

// 深拷贝 浅拷贝
1. 数组 
let arr=[1,2,34,5,6]
let arr2=arr
arr2[1]='test'
console.log(arr) //1,'test',34,5,6
console.log(arr2) //1,'test',34,5,6
//上述属于浅拷贝 
//深拷贝
let arr3=arr.slice(0) //arrayObj.slice(start, [end]) 该方法返回一个 Array 对象,其中包含了 arrayObj 的指定部分。不会改变原数组
//或者 let arr3=arr.concat()
arr3[1]='test'
console.log(arr) //1,2,34,5,6
console.log(arr3)  //1,'test',34,5,6

//2. 对象 
 1.深拷贝
let obj={
    name:'test',
    age:22
}
var deepCopy = function (source) {
    var result = {};            
    for(var key in source) {                
        if(typeof source[key] === 'object') {
            result[key] = deepCopy(source[key])
        } else {
            result[key] = source[key]
        }
    }            
    return result;
}

var objCopy = deepCopy(obj)
objCopy.name="WK"
console.log(obj)  //{name: "test", age: 22}
console.log(objCopy) //{name: "WK", age: 22}

2. 数组对象深拷贝
// 深拷贝
var deepCopy = function (o) {
    if (o instanceof Array) {
        var n = [];
        for (var i = 0; i < o.length; ++i) {
            n[i] = deepCopy(o[i]);
        }
        return n;

    } else if (o instanceof Object) {
        var n = {}
        for (var i in o) {
            n[i] = deepCopy(o[i]);
        }
        return n;
    } else {
        return o;
    }
}

JavaScript 数组对象去重

<!--删除指定元素-->

arr.splice(arr.findIndex(item => item.id == id), 1)


let data = [
  { id: 201801, name: '张三', age: 15, },
  { id: 201804, name: 'John', age: 18, },
  { id: 201802, name: '李四', age: 18, },
  { id: 201801, name: '张三', age: 15, },
  { id: 201805, name: 'Jack', age: 18, },
  { id: 201803, name: '王五', age: 10, },
  { id: 201805, name: 'Jack', age: 18, },
  { id: 201804, name: 'John', age: 18, },
  { id: 201805, name: 'Jack', age: 18, },
];
let hash = {};
data = data.reduce((preVal, curVal) => {
  hash[curVal.id] ? '' : hash[curVal.id] = true && preVal.push(curVal);
  return preVal
}, [])
console.log(Object.keys(data)) //下标
console.log(data,hash)

数组去重

//set 方法去重 
[... new Set(confimList)]

// 获取两数组交集并且保持结果元素唯一
var arr1=['0','3','5','5','6'],arr2=['4','8','10','5','5'];
var arr3 = arr2.filter(function(v){
	return arr1.indexOf(v)!==-1 // 利用filter方法来遍历是否有相同的元素
})
console.log([... new Set(arr3)])// 5

map操作

let arr=[{name:'nk'},{name:"wk"},{name:'mk'},{name:"bk"}]
let array=[]
  array=arr.map(res=>{
    console.log(res)
    return res
  }) // 需要return 不然是 undefined
console.log(array)

array 操作

  1. 常用方法
let list=[1,2,4,5,6,7]
list.splice(num, 1) // 删除指定下标项 并返回新的数组
list.shift(); //删除第一项
list.unshift() ;// 将某值添加到数组开头
list.pop();// 删除最后一项
list.push();// 添加到数组后
list.concat();// 拼接数组
//、、、splice操作、、、
var a = [1,2,3,4,5];   
var b = a.splice(2,2,7,8,9); //a:[1,2,7,8,9,5] b:[3,4]   
var b = a.splice(0,1); //同shift   
a.splice(0,0,-2,-1); var b = a.length; //同unshift   
var b = a.splice(a.length-1,1); //同pop   
a.splice(a.length,0,6,7); var b = a.length; //同push 

list.reverse();//反序

list.slice(start,end):返回从原数组中指定开始下标到结束下标之间的项组成的新数组 

list.join(separator):将数组的元素组起一个字符串,以separator为分隔符,省略的话则用默认用逗号为分隔符
  1. sort 排序
let arr = [11, 2, 13, 5, 7, 8]
    arr.sort((x, y) => {
      if(x<y){ //降序   x>y 升序
        return 1
      }
      // return 0
      // console.log(y)
    })
    console.log(arr)
    
 // 按照字母排序 a-z
 var list = [{name:'Google'},{name:'apple'},{name: 'Microsoft'}];
 list.sort((a,b)=>a.name.localeCompare(b.name,'zh'))

常用正则验证

//Email正则
var ePattern = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
用法:ePattern.test("99154507@qq.com") true

.replace(/(^\s*)/g,"") // 删除空格

// 正则验证
var myreg = /^1[345678]\d{9}$/; //手机号码验证
var nameReg = /^[A-Za-z\/\u4e00-\u9fa5]+$/; //姓名验证 
var reg = /^[0-9a-zA-Z]+$/; //只能输入字母和数字data
!myreg.test('29301938')//使用方法
//身份证 验证
checkIDCard(idcode) {
    // 加权因子
    var weight_factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    // 校验码
    var check_code = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];

    var code = idcode + "";
    var last = idcode[17];//最后一个

    var seventeen = code.substring(0, 17);

    // ISO 7064:1983.MOD 11-2
    // 判断最后一位校验码是否正确
    var arr = seventeen.split("");
    var len = arr.length;
    var num = 0;
    for (var i = 0; i < len; i++) {
      num = num + arr[i] * weight_factor[i];
    }

    // 获取余数
    var resisue = num % 11;
    var last_no = check_code[resisue];

    // 格式的正则
    // 正则思路
    /*
    第一位不可能是0
    第二位到第六位可以是0-9
    第七位到第十位是年份,所以七八位为19或者20
    十一位和十二位是月份,这两位是01-12之间的数值
    十三位和十四位是日期,是从01-31之间的数值
    十五,十六,十七都是数字0-9
    十八位可能是数字0-9,也可能是X
    */
    var idcard_patter = /^[1-9][0-9]{5}([1][9][0-9]{2}|[2][0][0|1][0-9])([0][1-9]|[1][0|1|2])([0][1-9]|[1|2][0-9]|[3][0|1])[0-9]{3}([0-9]|[X])$/;

    // 判断格式是否正确
    var format = idcard_patter.test(idcode);

    // 返回验证结果,校验码和格式同时正确才算是合法的身份证号码
    return last === last_no && format ? true : false;
  }  // 返回 true  false

// 根据身份证号得到姓别和精确计算年龄
function analyzeIDCard(IDCard,date) {
  var sexAndAge = {};
  //获取用户身份证号码
  var userCard = IDCard;
  //如果身份证号码为undefind则返回空
  if (!userCard) {
    return sexAndAge;
  }
  //获取性别
  if (parseInt(userCard.substr(16, 1)) % 2 == 1) {
    sexAndAge.sex = '1(男)'
  } else {
    sexAndAge.sex = '0(女)'
  }
  //获取出生年月日
  //userCard.substring(6,10) + "-" + userCard.substring(10,12) + "-" + userCard.substring(12,14);
  var yearBirth = userCard.substring(6, 10);
  var monthBirth = userCard.substring(10, 12);
  var dayBirth = userCard.substring(12, 14);
  //获取当前年月日并计算年龄
  var myDate = new Date(date);
  var monthNow = myDate.getMonth() + 1;
  var dayNow = myDate.getDay();
  var age = myDate.getFullYear() - yearBirth;
  if (monthNow < monthBirth || (monthNow == monthBirth && dayNow < dayBirth)) {
    age--;
  }
  //得到年龄
  sexAndAge.age = age;
  //返回性别和年龄
  return sexAndAge;
}

计算日期间隔

// 计算 出发日期和到达日期相差几天
function DateDiff(sDate1, sDate2) {  //sDate1和sDate2是yyyy-MM-dd格式

  var dateSpan,
    tempDate,
    iDays;
  sDate1 = Date.parse(sDate1);
  sDate2 = Date.parse(sDate2);
  dateSpan = sDate2 - sDate1;
  dateSpan = Math.abs(dateSpan);
  iDays = Math.floor(dateSpan / (24 * 3600 * 1000));

  return iDays;  //返回相差天数
}

倒计时

由于要获取时间戳 this.data.actEndTime格式最好为 :2019/02/12

countDown() {//倒计时函数
    // 获取当前时间,同时得到活动结束时间数组
    let newTime = new Date().getTime();
    let endTimes = this.data.actEndTime; // 结束日期
    let countDownArr;
    // 对结束时间进行处理渲染到页面
    
    let endTime = new Date(endTimes).getTime();
      let obj = null;
      // 如果活动未结束,对时间进行处理
      if (endTime - newTime > 0) {
        let time = (endTime - newTime) / 1000;
        // 获取天、时、分、秒
        let day = parseInt(time / (60 * 60 * 24));
        let hou = parseInt(time % (60 * 60 * 24) / 3600);
        let min = parseInt(time % (60 * 60 * 24) % 3600 / 60);
        let sec = parseInt(time % (60 * 60 * 24) % 3600 % 60);
        obj = {
          day: this.timeFormat(day),
          hou: this.timeFormat(hou),
          min: this.timeFormat(min),
          sec: this.timeFormat(sec)
        }
      } else {//活动已结束,全部设置为'00'
        obj = {
          day: '00',
          hou: '00',
          min: '00',
          sec: '00'
        }
      }
      countDownArr=obj;
    // 渲染,然后每隔一秒执行一次倒计时函数
    this.setData({ countDown: countDownArr })
    if (countDownArr.min == '00' && countDownArr.sec== '00'){
      // this.setData({status:2})
      return false 
    }
    setTimeout(this.countDown, 1000);
  }

Android 手机点击事件出现闪屏

相应元素添加:-webkit-tap-highlight-color:rgba(0,0,0,0)

避免全局变量污染

一、 使用全局唯一变量

只声明一个全局变量:

var maApp={
    //只要把多个全局变量都整理在同一个命名空间下,就能显著降低与其他应用程序、
    //组件或类库之间产生不可预知的相互影响的可能性,也使其可读性更高。
}

二、 使用全局唯一变量

使用闭包:

///创建一个函数,该函数包括,私有变量和一个特权对象,特权对象的内容是,利用闭包能访问到私有变量的函数,最后返回特权对象
var f3 = function() {
 var age = 18;
 return {
   name: "啊哈",
   age: age,
   gender: "男"
 }
}();
//获取变量
f3.name = "啊哈";

// 自执行函数

/*所有代码写在其中,在它内部声明的变量全部都是局部变量
,一般用来写完全独立的脚本*/
(function() {
 //我在一个匿名自执行函数中
 //some code here...
})()

判定this指向

判定 this 现在,我们可以按照优先顺序来总结一下从函数调用的调用点来判定 this 的规则了。按照这个顺序来问问题,然后在第一个规则适用的地方停下。

  1. 函数是通过 new 被调用的吗(new 绑定)?如果是,this 就是新构建的对象。

var bar = new foo()

  1. 函数是通过 call 或 apply 被调用(明确绑定),甚至是隐藏在 bind 硬绑定 之中吗?如果是,this 就是那个被明确指定的对象。

var bar = foo.call( obj2 )

  1. 函数是通过环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,this 就是那个环境对象。

var bar = obj1.foo()

  1. 否则,使用默认的 this(默认绑定)。如果在 strict mode 下,就是 undefined,否则是 global 对象。

var bar = foo()

四种规则将会以这种优先顺序施用于调用点:

通过 new 调用?使用新构建的对象。

通过 call 或 apply(或 bind)调用?使用指定的对象。

通过持有调用的环境对象调用?使用那个环境对象。

默认:strict mode 下是 undefined,否则就是全局对象。

小心偶然或不经意的 默认绑定 规则调用。如果你想“安全”地忽略 this 绑定,一个像 ø = Object.create(null) 这样的“DMZ”对象是一个很好的占位值,以保护 global 对象不受意外的副作用影响。

与这四种绑定规则不同,ES6 的箭头方法使用词法作用域来决定 this 绑定,这意味着它们采用封闭他们的函数调用作为 this 绑定(无论它是什么)。它们实质上是 ES6 之前的 self = this 代码的语法替代品。 以上,就是理解对于普通的函数调用来说的 this 绑定规则 所需的全部。