js基础学习3

120 阅读13分钟

正则

正则表达式

1.最简单的正则表达式

关键字原文本身/原文/ig

i:忽略大小写

g:global全局

2.备选字符集

【一个备选字符集】规定了【一位字符】可用的备选字符列表/[备选字符集]/

注意:

  • 一个[]只能匹配一位字符

  • 正则默认只要满足后,就不再管理后续操作,用户可任意输入

    • 解决:/^[备选字符集]$/ 要求从头到尾完全匹配
  • 若备选字符集中,unicode号连续,中间部分可用-代替

//例

[0123456789] => [0-9]
一位字母 [a-zA-Z]
一位汉字 [\u4e00-\u9fa5]
一位数字、字母、下划线 [0-9a-zA-Z_]
  • 除了x以外,其他都可以 [^x]

3.预定义字符集

已提供的常用字符集的简化

  • 一位数字 [0-9] \d

  • 一位数字、字母、下划线 [0-9a-zA-Z_] \w

  • 一位空白字符(\t \n 空格) \s

  • 一位除换行外的任意字符 .

不管是备选字符集还是预定义字符集,一个字符集都只能控制一个字

4.量词

规定了一个字符集出现的次数

  • 有明确数量

    • 字符集{n,m} 最少n次,最多m次

    • 字符集{n,} 最少n次,多列不限制

    • 字符集{n} 只能n次

  • 无明确数量

    • 字符集? 前面相邻的字符集可有可无,但最多一次

    • 字符集* 前面相邻的字符集可有可无,且不限制数量

    • 字符集+ 前面相邻的字符集至少一次,且不限制数量

5.指定匹配的位置

^开头 &结尾

注意:若^和&同时出现,前加^、后加&,要求从头到尾完全匹配

6.选择和分组

  • 选择|:在多个规则中,选择满足的规则执行 规则1|规则2

  • 分组() (规则1|规则2)

//例
/^\d|\w$/  //开头数字,结尾空格
/^(\d|\w)$/  //从头到尾,只能是空格或者数字
//电话的正则
/^(\+86|0086)?\s*1[3-9]\d{9}$/

7.预判

用于密码强度

//例
(?![0-9]+$)  //不能全由数字组成
(?![0-9A-Z]+$)  //不能全由数字或大写字母组成,也不能只由数字或大写字母组成

字符串中支持正则的API

1.分割

var arr=str.split(reg)

2.替换

  • 基本替换法 var newStr=str.replace(reg,"新内容")

默认只会替换第一个关键字,若想全部替换,结尾添加g

替换的内容只能是一个固定的新内容

  • 高级替换法
var newStr=str.replace(正则,function(a,b,c){
    console.log(a);//正则匹配到的关键字
    console.log(b);//正则匹配到的关键字下标
    console.log(c);//原文本身
    return a.length==2?"**":"***";
})
  • 格式化
//根据身份证号匹配出生日

var str="123123123412234567";

var newStr=str.replace(/(\d{6})(\d{4})(\d{2})(\d{2})(\d{4})/,function(a,b,c,d,e,f,g,h){
    console.log(a);//正则匹配到的关键字
    console.log(b);//是第1个分组获取到的内容
    console.log(c);//是第2个分组获取到的内容
    console.log(d);//是第3个分组获取到的内容
    console.log(e);//正则匹配到的关键字的下标
    console.log(f);//原文本身
    return c+"年"+d+"月"+e+"日";
})
	
console.log(newStr);

正则对象

1.创建正则对象

  • 直接量方法 var reg=/正则表达式/后缀

  • 构造函数:拼接正则情况使用 var reg=new RegExp("正则表达式","后缀")

2.方法

var bool=reg.test(user);结果:true/false

Math

专门提供了数学计算的API,不需要创建,直接使用

唯一的属性

Math.PI

API

1.取整

  • 上取整(超过一点就会取下一整数)Math.ceil(num)

  • 下取整(超多多少都会省略小数部分)Math.floor(num)

    • 上取整和下取整针对的对象小数位数都不能超过15位,超过会失效
  • 四舍五入取整 Math.round(num)

    四舍五入

    num.toFixed(d);即可四舍五入,又可自定义小数位数。结果为字符串

    parseFloat(num.toFixed(d));

//封装一个函数,实现可自定义保留小数位数且四舍五入
function round(num,d){
    num*=Math.pow(10,d);
    num=Math.round(num);
    num/=Math.pow(10,d);
    return num;
}
console.log(round(Math.PI,3));

2.乘方和开方

  • 乘方Math.pow(底数,幂)

  • 开方Math.sqrt(num) 只能开平方

3.最大值/最小值

Math.max/min(a,b,c,d,...)

问题:不支持数组参数 ==> 解决:Math.max/min.apply(Math,arr);

apply:①自己没有的方法,可以去借用;②可将数组打散为单个参数进行传入

4.绝对值

Math.abs(num) 将负数转为正数

5.随机数

Math.random(); 0-1的随机数(可能取到0,但无法取到1)

只要页面具有随机功能,底层均为随机数

重要使用方法

Math.random()*(max-min+1)+min;

parseInt(Math.random()*(max-min+1)+min);

Date

封装了日期对象,提供了对日期事件进行操作的API

创建日期对象

  • 当前时间 var now=new Date();

  • 自定义时间1 var birth=new Date("yyyy/mm/dd h:m:s");

    • 自己创建,放入“年/月/日 时:分:秒”

    • 时分秒可以省略,未写时默认00:00:00

  • 自定义时间2 var birth=new Date(yyyy,mm,dd,h,m,s);

    • 月份需要修正,默认从0开始到11
  • 复制一个日期对象 var end=new Date(now);

    • 因为日期对象的API都是直接修改原对象,使用API后无法保存旧值,调用API后无法保存旧值 => 调用API前先复制保存
  • var x=new Date(毫秒数);

计算器保存的时间初始值:1970年1月1日 8:00:00

操作

1.减法

两个日期对象相减,得到的是毫秒差 ==> 日期对象保存的是毫秒

2.API

分量:FullYear Month Date Day Hours Minutes Seconds

  • 每一个分量都有一对方法getxx/setxx ()

    • 取值范围:年(当前年份)、月(0-11)、日、时(0-23)、分(0-59)、秒(0-59)

    • 星期Day:只有get,没有set,取值0-6(0是星期天)

  • 对某个日期直接做加减 date.setFullYear(date.getFullYear()+3);

  • 将日期格式化为字符串

date.toLocaleString();

+ 优点:转为String,可以使用String的API

+ 缺点:具有浏览器兼容性

解决:自定义format函数

Number Boolean

所有引用类型底层都具有构造函数创建方式(除Math),直接量法是后续追加的简化操作

var num=new Number();

var bool=new Boolean();

num.toString();

num.toFixed(d);//结果是一个字符串

Error

1.浏览器自带的4种错误类型

  • 语法错误:SyntaxError --常为符号错误

  • 引用错误:ReferenceError --未创建就使用了

  • 类型错误:TypeError --有这个方法,但不是这个类型的方法

  • 范围错误:RangeError --只有num.toFixed(d)会有这个错误,d的范围:0-100

2.错误处理

当程序发生错误时,保证程序不会异常中断的机制

try{
    可能出错的代码
}catch(err){
    console.log(err);//提示用户错误的原因
}

但try...catch语句执行效率低 ==> if...else

3.抛出自定义错误

throw new Error("自定义错误信息")

Function

创建

  • 声明方式:

    function 函数名(形参){函数体; return 结果;}具有完整的声明提前

  • 直接量方式

    var 函数名=function(形参){函数体; return 结果;}有声明提前,但赋值留在原地

  • 构建函数法:

    var 函数名=new Function("形参",...,"函数体")函数体在动态拼接时使用

调用

  • 函数名();

  • 元素.onclick

重点

1.创建:3种方式

2.作用域

  • 全局:哪里都可以使用

  • 函数:只能在函数调用时内部使用

  • 变量的使用规则:优先使用局部,局部没有找全局,全局没有则报错

3.声明提前

在程序正式执行前,会将var声明的变量和function声明的函数集中提前到当前作用域顶部,但赋值留在原地

4.按值传递

  • 原始类型之间 互不影响

  • 引用类型之间 相互影响

5.重载

相同的函数根据传入的实参不同,会自动选择相应函数执行

目的:减少程序员负担

注意:js不支持重载,因为js不允许同时存在多个同名函数,最后一个会覆盖之前的所有函数

arguments 函数内部使用,类数组:下标、length、遍历

作用:可以借助实参,则不需要创建形参

使用arguments实现重载:通过判断arguments,实现功能

//传入一个实参做乘方,传入两个实参做加法
function f1(){
    if(arguments.length==1){
        return Math.pow(arguments[0],2);
    }else if(arguments.length==2){
        return arguments[0]+arguments[1];
    }
}
console.log(f1(8));
console.log(f1(8,9);

6.匿名函数

无名字的函数,被没有变量名/函数名引用着,调用完毕后会立即释放

  • 匿名函数自调(function(){函数体;})()

  • 匿名函数回调:某个函数调用时,传入的实参是一个函数,且不需要调用执行

//例
arr.sort(function(a,b){return a-b;})
str.replace(reg,function(){})

认识回调函数: 匿名函数不是自调就是回调

7.闭包

函数的执行原理

① 程序在加载时:创建执行环境栈(ECS),首先压入全局执行环境(全局EC),全局EC中引用着全局对象window,window中保存着全局变量

② 定义函数时:创建函数对象,封装函数的定义。在函数对象中创建scope属性(记录自己来自的作用域)。全局函数的scope是window

③ 调用函数前:在执行环境栈中压入新的函数EC。创建活动对象AO,保存着本次函数调用时用到的局部变量。在EC中添加scope chain属性引用AO,设置AO的parent属性为函数的scope对象

④ 调用时:变量的使用规则是有限使用局部,局部没有找全局,全局没有报错

⑤ 调用完:函数的EC会出栈,AO会自动释放,故局部变量自动释放

作用域链scope chain

  • 概念:以EC中的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构,称为作用域链

  • 作用:查找变量

闭包

  • 概念:保护一个可以【反复使用的局部变量】的一种词法结构,结合了局部和全局的优点

  • 使用步骤:

    • 创建一个外层函数

    • 在其中创建一个受保护的局部变量

    • 外层函数调用要返回内层函数,此内层函数在操作受保护的变量

  • 缺点:受保护的变量永远无法释放,用多了会导致内存泄漏

  • 闭包的重点:

    • 判断闭包,找到受保护的变量,确定其值

    • 外层函数调用几次,就创建了几个闭包,受保护的变量就有了几个副本

    • 同一外层函数调用,返回的内层函数,都是在使用同一个受保护的变量

//语法
function 外层函数(){
    受保护的变量;
    return function(){
        不断操作受保护的变量;
        return 结果;
    }
}
var 内层函数=外层函数();
  • 开发:防抖节流
    • elem.onmousemove 鼠标移动事件,每次移动都会触发

    • input.oninput input每次修改都会触发的事件

    • window.onresize 屏幕每次改变大小都会触发

    不会减少函数执行次数,但会减少DOM树渲染,DOM数据渲染的次数越频繁页面的效率越低下
//防抖节流
function fdjl(){
    var timer=null;
    return function(){
        if(timer){clearTimeout(timer)}//判断有无定时器,有则清除
        timer=setTimeout(function(){
            操作;
        },毫秒数)
    }
}
var animate=fdjl();

Object

面向对象: 在程序中使用对象描述现实中的一个事物

  • 现实事物的属性 => 对象的属性

  • 现实事物的方法 => 对象的函数

  • 现实中的所有数据都必须包含在事物中才有具体意义

面向对象和面向过程

  • 面向过程:开头->中间->结束,一直使用的开发方法

  • 面向对象:对象则包含属性和方法,如轮播对象、选项卡对象

10个引用类型都是对象(浏览器内置对象)

封装/创建/定义/声明/实例化:自定义创建对象

1.直接量法

var obj={"属性名":"属性值","方法名":function(){},}

注意:

  • 属性名和方法名的""可以省略,但通常不省略,因为JSON必须添加""

  • 访问对象属性和方法

    • obj.属性名;=== obj["属性名"];

    • obj.方法名()=== obj["方法名"]();

  • 访问到不存在的属性:undefined(下标越界)

  • 可在后续随时添加想要的东西 obj.新属性名="属性值";

this 在当前对象的方法内,指向的当前调用方法对象

① 单个元素绑定事件 this -> 单个元素

② 多个元素绑定事件 this -> 当前元素

③ 函数 this -> 当前调用函数的对象

④ 构造函数中 this -> 当前创建的对象

⑤ 定时器 this -> timer

2.预定义构造函数法

var obj=new Object();//创建一个空对象

obj.属性名=属性值;

obj.方法名=function(){};

3.自定义构造函数法

  • 创建一个构造函数function 类名(形参,...){this.属性名=形参1;...}

  • 反复调用构造函数,创建出多个对象var x=new 类名(实参,...);

  • 遍历 for(var i in obj){obj[i]}

  • 优点

    • 所有操作都包含在一个对象中

    • 维护效率高

    • 一个方法调用,触发了很多操作

继承

父元素的成员(属性和方法),子对象可以直接使用

为什么继承:代码重用,节约内存空间

何时继承:只要多个子元素公用的属性和【方法】,都应集中在父元素中

js的面向对象是基于原型(父元素)的

原型

保存着一类子对象共有属性和共有方法的原型对象(父元素)

  • 如何找到原型对象

    • 对象名.__proto__ 至少要创建一个对象才能使用本方法

    • 构造函数名.prototype

      new 构造函数(Object/RegExp/Date/Function/String/Number)

  • 在原型对象中添加共有属性和共有方法

    原型对象.属性名=属性值;

    原型对象.方法名=function(){}

    • 每个对象都有一个.__proto__的属性指向着自己的原型

    • 每个构造函数都有一个.prototype属性指向自己的原型

  • 原型链: 自己没有的属性和方法,可以顺着原型链向上找,直到最顶层(Object.prototype)

    • 作用:查找属性和方法
  • 自有和共有

    • 自有:保存在对象本地

    • 共有:保存在原型对象中,子对象都可以直接使用

常见问题

1.判断一个属性是自有还是共有

自有

obj.hasOwenPrototype("属性名");

true -> 自有; false -> 可能共有,也可能没有

共有: 2个条件

obj.hasOwenPrototype("属性名")==false;//判断不是自己

"属性名"in obj;//in关键字会查找自己的原型

//判断自有、共有
if(obj.hasOwenPrototype("属性名")){
    console.log("自有");
}else{
    if(obj.hasOwenPrototype("属性名")=false&&"属性名" in obj){
        console.log("共有");
    }ekse{
        console.log("没有");
    }
}

2.修改/删除属性

自有

修改 obj.属性名=新值;

删除 `delete obj.属性名;

共有: 找到原型再做操作

修改:不要在本地做操作,会导致在本地添加上一个同名属性,优先使用自己的,但没有修改原型

删除:不要再本地做操作,本地操作无效果

3.为一类人添加方法

//为老IE数组添加indexOf方法
if(Array.prototype.indexOf===undefined){
    Array.prototype.indexOf=function(key,starti){
        starti===undefined&&(starti=0);//设置默认值
        for(var i=starti;i<this.length;i++){
            if(this[i]==key){
                return i;
            }
        }
        return -1;
    }
}

4.判断x是否是数组

方法1

判断当前对象是否是继承自Array.prototype

Array.prototype.isPrototype(x);也可以判断其他类型

true:数组

方法2

判断当前对象是否是由此构造函数创建

x instanceof Array;也可判断其他类型

true:数组

方法3

Array.isArray(x);只有数组有这个方法

true:数组

方法4

使用多态来判断x是否是一个数组:在Object的prototype中保存着最原始的toString方法

原始的toString输出的结果:[object 构造函数名]

if(Object.prototype.toString.apply(arr)==="[object Array]"){
       数组
}

多态: 子对象觉得父对象提供的方法不好用,可在本地定义一个同名成员,有限使用离自己更近的方法(同一函数名,但不是同一个方法)

5.如何设置自定义继承

  • 设置单个对象的继承:obj.__proto__=新对象;

  • 设置多个对象的继承:(创建对象前要设置好父对象)

    构造函数名.prototype=新对象;

两链一包

闭包 保护一个可以【反复使用的局部变量】的一种词法结构

作用:结合全局和局部的优点

作用域链 以EC中的scope chain属性为起点,经过AO逐级隐痛,形成的一条链式结构

作用域链:查找变量

原型链 自己没有的属性和方法,可以顺着原型链向上找至最顶层(Object.prototype)

原型链作用:查找属性和方法