JavaScript学习

471 阅读8分钟

一、如何用js判断null值

以下是不正确的方法:

var exp=null;
if(exp==null){
    alert('is null')
}

exp为undefined时,也会得到与null相同的结果,虽然nullhe undefined不一样。

注意:要同时判断null和undefined时课使用如上方法

let exp=null;
if(!exp){
    alert("is null")
}

如果exp为undefined,或者数字0,或false,也会得到与null相同的结果,虽然null和二者不一样。

注意:要同时判断null、undefined、数字零、false时课使用如上方法。

let exp=null;
if(typeof exp=='null'){
    
}

为了向下兼容,exp 为 null 时,typeof null 总返回 object,所以不能这样判断。

let exp=null;
if(!exp && typeof exp!="undefined" && exp!=0){

}

typeof exp!=“undefined” 排除了 undefined

exp!=0 排除了数字零和 false。

一、JavaScript数组

1. 遍历类(只有直接对item操作才会改变,返回值需要特别注意)

        forEach    map   filter   find    some    every    for遍历  

arr.forEach()

arr.forEach((val,index,arr)=>{

console.log(val,index,arr)

})

arr.map() //非常有用,做数据交互“映射”

                 //正常情况下,需要配合return,返回是一个新的数组

                 //若没有return,相当于forEach

注意:使用map,一定要return

arr.filter()过滤,过滤一些不合格“元素”,如果回调函数返回true,就留下

var ages=[1,2,3,4,5]

    function checkoutAdult(age){

          return age>=2;

    }

    let newArr = ages.filter(checkoutAdult)

console.log(newArr) //[2,3,4,5]

2. 增加删除类(改变原数组,返回值需要特别注意)

    push && pop 

    push是从后面加一项,返回值是增加后的数组长度

    pop是从后面删除一项,返回值是删除的那一项

    shift  && unshift     

    shift是从前面删除一项,返回值的删除的那一项

    unshift从前面加入一项,返回值是增加后的数组长度

    splice  a.splice(n,m,l,...)

从第n项(包括n)删除m项,把l,…插入到n前面,返回值是删除的数组,原有数组改变。没     有第三项的时候表示只删除。没有2,3项的时候表示从第n项删除到最后。

 3. 截取和拼接(原有数组不变)

  **   slice    slice(n.m)**

     从第n项(包括n)开始截取到m项(不包括m),没有第二项表示到末尾。**返回一个截取的      新数组,**不改变原数组,支持负数索引。

    concat    a.concat(b,c)

传参是想要拼接的数组/值,可以是多项传参,返回值是拼接后的新数组

4. 顺序相关(改变原数组,返回值为预期结果)

  **  reverse**

    a.reverse()倒过来,改变原数组,返回来值为预想结果

    sort  

    项目中sort都要有传参,改变原数组,返回来值是排序后的数组

5. 数组去重

二、js语法区别

export和export default的区别:

export导出**需要使用{}将对应的模块导出,同时在使用是import导入时需要使用{}**来引入相应的模块

export default导出时,不用使用{}进行导出对应的模块、函数、文件等。但是只能导出一个。同时import导入时也不用{}实现导入

module.exportsexports都是node端在用,两者指向同一内存块,

module有一个exports,用于给module.exports添加属性。*****同时import导入时需要用{}实现导入。

二、处理数据

/** * 将价格转为分展示 * @method handlePrice * @params {number} price: 价格 * @return {string} 处理后的价格 */ function handlePrice(price) {  if (typeof price === 'number') {    let priceStr = price.toString();    let integerNum = 0; // 当前整数    let decimalsNum = 0; // 小数    let currentPrice = ''; // 处理后的数量    integerNum = priceStr.slice(0, priceStr.length - 2);    integerNum = integerNum.length < 1 ? `0` : integerNum;    decimalsNum = priceStr.slice(priceStr.length - 2, priceStr.length);    decimalsNum = decimalsNum.length === 2 ? decimalsNum : `0${decimalsNum}`;    currentPrice = Number(`${integerNum}.${decimalsNum}`).toFixed(2);    return currentPrice;  } else {    throw new Error('处理价格传递的不是数值类型')  }}

// 时间戳处理成2019.12.23
function dateTime(date){  
    var dateTime=new Date(parseInt(date))  
    var year=dateTime.getFullYear();  
    var month=dateTime.getMonth()+1;  
    var day=dateTime.getDate();  
    if(month<=9){    
    month='0'+month  
    }  
    if(day<=9){   
    day='0'+day 
     }  
    var timeDay=year+'.'+month+'.'+day;  return timeDay;
}

//时间戳转换成日期时间1995.07.06 12:30:50
    function js_date_time(unixtime) {  
    var dateTime = new Date(parseInt(unixtime))  
    var year = dateTime.getFullYear();  
    var month = dateTime.getMonth() + 1;  
    var day = dateTime.getDate();  
    var hour = dateTime.getHours();  
    var minute = dateTime.getMinutes();  
    var second = dateTime.getSeconds();  
    var now = new Date();  
    var now_new = Date.parse(now.toDateString());  //typescript转换写法  
    var milliseconds = now_new - dateTime;  
    if(month<=9){    
        month='0'+month  
    }  
    if (day <= 9) {    
        day = '0' + day  
    };  
    if (hour <= 9) {    
        hour = '0' + hour  
    };  
    if (minute <= 9) {    
        minute = '0' + minute  
    };  
    if(second<=9){    
        second='0'+second  
    }  
    var timeSpanStr = year + '.' + month + '.' + day + ' ' + hour + ':' + minute + ':' + second;  return timeSpanStr;}

// 处理手机号码为156****6776
    function jsonTel(number){  
        let tel = number.replace(number.substring(3, 7), "****")  
        return tel;
    }

// 处理券码为1234-5678-9012
    function couponCode(code){  
    let couponCode = code.substring(0, 4) + '-' + code.substring(4, 8) + '-' + code.substring(8, 12);  return couponCode;}

// 把时间2019-12-23处理成2019年12月23日
    function ymd(date){  
    let newTime=date.split('-');  
    let year = newTime[0] + '年' + newTime[1] + '月' + newTime[2] + '日'  
    return year;
    }


// 获取当月时间的第一天和第二天
    function getFullDate(targetDate) {  
        var D, y, m, d;  
        if (targetDate) {    
            D = new Date(targetDate);    
            y = D.getFullYear();    
            m = D.getMonth() + 1;    
            d = D.getDate();  
        } else {    
            y = fullYear;    
            m = month;    
            d = date;  
        }  
        m = m > 9 ? m : '0' + m;  
        d = d > 9 ? d : '0' + d;  
        return y + '-' + m + '-' + d;
    };

//在其他页面页面运用
// 获取当月的第一天和最后一天    
var nowDate = new Date();    
var cloneNowDate = new Date();    
var fullYear = nowDate.getFullYear();    
var month = nowDate.getMonth() + 1; // getMonth 方法返回 0-11,代表1-12月    
var endOfMonth = new Date(fullYear, month, 0).getDate(); // 获取本月最后一天     
var endDate = utils.getFullDate(cloneNowDate.setDate(endOfMonth));//当月最后一天    
var starDate = utils.getFullDate(cloneNowDate.setDate(1));//当月第一天

//40分50秒
function remainTime(time) {      
    var minute = Math.floor(time / (60 * 1000));      
    var second = Math.floor((time % (60 * 1000)) / 1000)      
    return minute + '分' + second + '秒'
}


//支付功能
function requestPayment(typeId, contentId, contentShardId, anonymous, subTypeId, callback) {
  dataApi.pay.getUniteOrder({
    typeId: typeId,
    contentId: contentId,
    subTypeId: subTypeId,
    contentShardId: contentShardId,
    openId: wx.getStorageSync('openId'),
    anonymous: anonymous,
    app: getApp().globalData.app
  }).then(function (res) {
    if (res.result.error) {
      wx.showModal({
        title: '提示',
        content: res.result.error,
        confirmText: '我知道了',
        confirmColor: '#ff8022',
        showCancel: false
      })
    } else {
      wx.showLoading({
        title: '支付中...',
        mask:true
      })
      wx.requestPayment({
        'timeStamp': res.result.timeStamp,
        'nonceStr': res.result.nonceStr,
        'package': res.result.package,
        'signType': res.result.signType,
        'paySign': res.result.paySign,
        'success': function (res) {
          wx.hideLoading();
          callback()
        },
        'fail': function (res) {
          wx.hideLoading();
          wx.showToast({
            title: '支付失败',
            icon: 'none',
            mask: true,
            duration: 2000
          })
        }
      })
    }

  }, function (msg) {
    console.log(msg)
  })
}


//判断是否是电话号码
function isPhone(tel){
      var regx=/^1[34578]\d{9}$/;
      return regx.test(tel)
}
console.log(isPhone(1562736776))//返回true和false


//验证是否是邮箱
function isEmail(email) {
      var regx = /^([a-zA-Z0-9_\-])+@([a-zA-Z0-9_\-])+(\.[a-zA-Z0-9_\-])+$/;
      return regx.test(email);
}


//验证是否是身份证
function isCardNo(number) {
    var regx = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
    return regx.test(number);
}

//去空格
trim:function(value){
    return value.replace(/(^\s*)|(\s*$)/g,"")
}

//格式化手机号码
formatNumber:function(num){
    return 
}

//所谓的数字千分位形式是从个位数起,每三位之间加一个逗号,例如:1450068经过处理之后1,450,068

方法一:利用字符串提供的toLocaleString()方法处理,此方法最简单
const num=1450068;
console.log(num.toLocaleString())//1,450,068

方法二:
function toThousand(num){      
    var result=[];      
    var counter=0;      
    num=(num||0).toString().split('');      
        for(var i=num.length-1;i>=0;i--){        
            counter++;        
            result.unshift(num[i]);        
            if(!(counter%3)&&i!=0){          
                result.unshift(',')        
          }      
        }      
    return result.join('')   
  } 
  console.log(toThousand(111222333444))//111,222,333,444


//把数字大于10000的显示成1万(把5位数显示成万),把类似小于1000的显示成原来的1000(把四位数显示成4位)
function handlethousand(number) {  
    var number2 = parseFloat(number)  
    var number1 = number2.toString();  
    if (number1.length > 4) {    
        return number1 / 10000 + '万'  
        }  else{    
            return number1  
       }}

let list = this.data.list;    
//使用map方法要return val要不然就不显示
// let list2 = list.map((val, index) => {    
//   console.log(handlethousand(val.num))    
//   val.num = handlethousand(val.num)    
//   return val    
// })  
//使用forEach的话不能let list2=,要不然就没用  
list.forEach((val,index)=>{      
    val.num = handlethousand(val.num)    
})    
this.setData({      
    list: list    
})


// 处理时间戳js转化为几天前,几小时前,几分钟前,几年前
const getDateDiff=dateTimeStamp=>{    
    var minute=1000*60;//一分钟等于60秒    
    var hour=minute*60;//1小时等于60分钟    
    var day=hour*24;//1天等于24小时    
    var halfmonth=day*15;    
    var month=day*30;//一个月有30天    
    var year=day*365;//一年有365天    
    var now=new Date().getTime();//通过原型方法直接活佛当前时间的毫秒值,准确    
    var diffValue=now-dateTimeStamp;    
    var result;//返回来的    
    if(diffValue<0){        
        return;    
    }    
    var yearC=diffValue/year;    
    var month=diffValue/month;    
    var weekC=diffValue/(7*day);    
    var dayC=diffValue/day;    
    var hourC=diffValue/hour;    
    var minC=diffValue/minute;    
    if(yearC>=1){        
        result=''+parseInt(yearC)+'年前';    
    }    
    if(monthC>=1){        
        result=""+parseInt(monthC)+'月前';   
    }else if(weekC>=1){        
        result=""+parseInt(weekC)+'周前';    
    }else if(dayC>=1){        
        result=""+parseInt(dayC)+'天前';    
    }else if(hourC>=1){        
        result=""+parseInt(hourC)+'小时前';    
    }else if(minC>=1){        
        result=""+parseInt(minC)+'分钟前';    
    }else{        
        result="刚刚";    
    }    
    return result; 
    }

//数组中每5条数据添加一条数据,分页功能每页显示10条才行
let arr1 = [{        
name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },      {        name: 'yier',        age: 18      },
    ]    
console.log(arr1.length)    
var arr2 = arr1.slice(0, 5)    
console.log(arr2)    
let newAd = [{      
    name: '黄意芳',      
    age: '18'    
}]    
let arr4 = arr1.slice(5);    
let newList = arr2.concat(newAd).concat(arr4).concat(newAd)    
console.log(newList)

//把分转化成


//String.replace(/\s/g,'')中的/\s/g表示什么意思
'/\s/g'中的/xxx/表示正则表达式,'\s'表示正则匹配字符串中的空字符,'g'表示全部匹配

三、ES6语法

1. ES6简介

    全称ECMAScript6.0,是JavaScript的下一个版本标准,2015.06发版

    JavaScript语言的国际化标准

2. let和const

    let 声明的变量只在let命令所在的代码块内有效。

1letvar关键字的用法基本一样
let food='西兰花的用法基本一致'
food='西兰花炒花菜'
console.log(food)

2let没有变量提升,变量的声明:会提升到当前作用域的顶端

    const声明一个只读的常量,一旦声明,常量的值就不能改变

3. 解构赋值

    注意:对于做交互特别有用,ajax

    let [a,b,c]=[1,2,3]

    注意:左右两边,结构格式要保持一致

let json = {      
    name: '意儿',      
    age: 18,      
    color: "white"    
}
let { name, age, color } = json;
let { name: n, age: a, color: c } = json   //改为另外的名字 

解构时候可以给默认值
let [a,b,b="默认值"]=['aaa','bbb']

4. 字符串模板以及字符串新增

(1) 字符串模板:

             优点:可以随意换行

                      `${变量名称}`   

 (2)关于字符串一些东西

             字符串查找:

                            str.indexOf(要找的东西)   返回索引(位置),没找到返回-1

                            str.includes(要找的东西)   返回值true/false

(3)字符串是否以谁开头

              str.startWith(检测东西)

(4)字符串是否以谁结尾

              str.endsWith(检测东西)

    重复字符串:

              str.repeat(次数)

    填充字符串:

str.padStart(整个字符串长度,填充东西) 往前填充

              str.padStart(整个字符串长度,填充东西) 往后填充

              let str="意儿";

              let padStr="亲爱的";

              str.padStart(str.length+padStr.length,padStr) ==亲爱的意儿 

   5、函数默认参数、箭头函数、剩余参数

     1、函数默认参数

          function show(x=0,y=0){

              console.log(x,y)

          }

         show()

     2、函数参数默认已经定义了,不能再使用let,const声名

         function show(a=1){

             let a=10;//不能此处是错误

             console.log(a)

          }

          show()

    扩展运算符、Rest运算符

             [1,2,3,4] ...[1,2,3,4] ===1,2,3,4

             1,2,3,4 ...1,2,3,4 ===[1,2,3,4]

    箭头函数

          ()=>{

             语句

             return

          }

    注意:

         1、this问题,定义函数所在的对象,不在是在运行的对象时所在的对象

         2、箭头函数里面没有arguments,用‘...’

         3、箭头函数不能当构造函数 

function省略掉,替换为=>
参数只有一个时,可以省略()
函数体只有一行时,可以省略{}
函数体只有一行时,并且有返回值时,如果省略了{},必须盛磊return
//无参数,一行,无返回值的 函数
let func1=function(){
    console.log('hello ITheima')
}
let func1=()=>console.log('hello ITheima')

//1个参数,一行,无返回值函数
let func2=function(p1){
    console.log(p1)
}
let func2=p1=>console.log(p1)

//2个参数,多行,无返回值的函数
let func3=function(p1,p2){
    console.log(p1)
    console.log(p2)
}
let func3=(p1,p2)=>{
    console.log(p1)
    console.log(p2)
}

//无参数,一行,有返回值的函数
let func4=function(){
    return 'ITheima'
}
let func4=()=>'ITheima'
let func4Res=func4()

//1个参数,一行,有返回值的函数
let func5=function(p1){
    return p1+'IThemia'
}
简写:
let func5=p1=>p1+'IThemia'
let res=func5('深圳')

//2个参数,多行,有返回值的函数
let func6=function(p1,p2){
    console.log(p1,p2)
    return p1 + p2 + 'ITheima'
}
简写:
let func6=(p1,p2)=>{
    console.log(p1,p2);
    return p1+p2+'ITheima'
}
func6('深圳','黑马')

5、async函数(关于async里面try/catch的一个问题)

ES2017标准引入了async函数,使得异步操作变得更加方便
它是Generator函数的语法糖

1、try....catch是同步代码

2、异步,已经脱离了当前的主线程,可以想象成一个新的定时任务里去执行;只是能与主线程共享内存,堆栈等

async函数有多种使用形式

//函数声明
async function foo(){}

//函数表达式
const foo=async function(){}

//对象的方法
let obj={
   async foo(){}
}
obj.foo().then(){}

//Class的方法
class Storage{
    construtor(){
        this.cachePromise=caches.open("avatars")
    }
    async getAvatar(name){
        const cache=await this.cachePromise;
        return cache.match(`/avatars/${name}.jpg`)
    }
}

const storage=new Storage();
storage.getAvatar('jake').then(())

//箭头函数
const foo=async ()=>{};

3、返回Promise对象

async函数返回一个Promise对象。

async函数内部return语句返回的值,会成为then方法回调函数的参数

async function f(){
    return 'hello world'
}

f().then((v)=>{
    console.log(v)

})

6、this指向及改变this指向的方法

一、函数的调用方式决定了this的指向不同

1.普通函数调用,此时this指向window

function fn(){
    console.log(this);//window
}
fn();//window.fn(),此处默认省略widow

2.构造函数调用,此时this指向实例对象

function Person(age,name){
    this.age=age;
    this.name=name;
    console.log(this) //此次this分别指向Person的实例对象p1,p2
}
var p1=new Person(18,'zs')
var p2=new Person(18,'ww')

3、对象方法调用,此时this指向该方法所属的对象

var obj={
    fn:function(){
        console.log(this);//obj
    }
}
obj.fn()

4、通过事件绑定的方法,此时this指向绑定事件的对象

<body>
    <button id="btn"></button>
<script>
    var oBtn=document.getElementById("btn");
    oBtn.onclick=function(){
        console.log(this);//btn
    }
</script>
</body>

5、定时器函数,此时this指向window

setInterval(function(){
    console.log(this);//window
},1000)

二、更改this指向的三个方法

1、call()方法

var Person={
    name:'lixue',
    age:21
}
function fn(x,y){
    console.log(x+","+y)    
    console.log(this)//这里指向的是window
}
fn('hh',20)

没错,就像上面说的,普通函数的this指向window,现在让我们更改this指向

var Person={
    name:"lixue",
    age:21
}
function fn(x,y){
    console.log(x +","+y)
    console.log(this)
    console.log(this.name)
    console.log(this.age)
}
fn.call(Person,'哈哈',20)  //这样就指向Person

2、apply()方法

apply()与call非常相似,不同之处在于提供参数的方式,apply()使用参数数组,而不是参数列表

3、bind()方法

bind()创建的是一个新的函数(称为绑定函数),与被调用函数有相同的函数体,当目标函数被调用时this的值绑定到bind()的第一个参数上。

三、改变this指向的例子

var oDiv1=document.getElementById("div1");
oDiv1.onclick=function(){
    setTimeout(function(){
        console.log(this)//这里是window
    },1000)
}
定时器里的this指向window,那么如何改成指向div呢

oDiv1.onclick=function(){
    setTimeout(function(){
        console.log(this)//这里是对象div
    })
}

因为在定时器外,在绑定事件中的this肯定指向绑定事件的对象div,用call和apply都行,
上图就是用bind改变了this指向

四、JavaScript的基础学习

1、JavaScript数据类型

值类型(基本类型):

字符串(String) 数字(Number) 布尔(Boolean) 对空(Null) 未定义(Undefined) Symbol

引用数据类型:

对象(Object)  数组(Array)   函数(Function)

2、对象(包括属性和方法)

var person={
    firstName:'John',
    lastName:'Doe',
    age:50
}

访问对象属性(两种方法)
person.lastName

person["lastName"]



3、encodeURL和encodeURLComponent的作用及应用

将文本字符串编码为一个有效的统一资源标识符(URL)

最多使用的应为encodeURLComponent,它是将中文、韩文等特殊字符转换成utf-8格式的URL编码,所以如果给后端传递参数需要使用encodeURLComponent时需要后台解码对utf-8支持。

4、replace

replace(/\/g,'')   作用是把/替换成''
例如:
var aa="adsdd/ssss/"
var bb=aa.replace(/\//g,"")  adsddssss

js正则去除html代码里img标签里的style
replace(/<img/g, "<img style=\"display:none;\"")   

5.module.exports

//导出
module.exports={
    title:'yier'
}

//引入
const defaultSetting=require('文件的路径')

//使用
defaultSetting.title

6、es6:export default和export区别

1exportexport default均可用于导出常量、函数、文件、模块等
2、你可以在其他文件或模块中通过import+(常量|函数|文件|模块)名的方式,将其导入,
以便能够对其进行使用
3、在一个文件或模块中,exportimport可以有多个,export default仅有一个
4、通过export方式导出,在导入时要加{} ,export default则不需要

1.export
//a.js
export const str = "blablabla~";
export function log(sth) { 
  return sth;
}
对应的导入方式:

//b.js
import { str, log } from 'a'; //也可以分开写两次,导入的时候带花括号

2.export default
//a.js
const str = "blablabla~";
export default str;
对应的导入方式:

//b.js
import str from 'a'; //导入的时候没有花括号

使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名

//a.js
let sex = "boy";
export default sex(sex不能加大括号)
//原本直接export sex外部是无法识别的,加上default就可以了.但是一个文件内最多只能有一个export default。
其实此处相当于为sex变量值"boy"起了一个系统默认的变量名default,自然default只能有一个值,所以一个文件内不能有多
个export default// b.js
本质上,a.js文件的export default输出一个叫做default的变量,然后系统允许你为它取任意名字。所以可以为import的模块起任何变量名,且不需要用大括号包含
import any from "./a.js"
import any12 from "./a.js" 
console.log(any,any12)   // boy,boy

//导出
module.exports={
    title:'题目',
    showSetting:false
}
//导入
import defaultSettings from '@/setting'
const {title,showSetting} = defaultSettings