JavaScript 高级
作者: 写代码的小鱼儿
Email:282505458@
QQ:282505458
微信:15311464808
说明:本文档用于学习交流,可传播可分享,如有错误,请联系小鱼儿,感谢矫正与探讨
创建对象的三种方式
对象字面量
对象名 = {}
var obj = {name : '张三',age : 20,say : function () {console.log('say...');}}
系统构造函数,工厂模式
对象名 = new Object();
function createObject (name,age) {var obj = new Object();obj.name = name;obj.age = age;obj.say = function () {console.log('say....');}}
自定义构造函数
原理同工厂模式,方法名首字母大写。自定义构造函数自动做了四件事:
a: 在内存中创建新的对象
b: this 指向这个对象
c: 给这个对象添加属性和方法
d: 返回这个新对象
function Person (name,age) {this.name = name;this.age = age;this.say = function () {console.log('say...');}}
检测对象是否是某个构造函数实例化的结果
(1)对象.instanceof.构造方法
(2)对象.constructor == 构造方法
工厂模式创建对象与构造函数创建对象的区别
工厂模式:
函数名小驼峰命名法,函数内部有new,返回值为所创建对象。直接调用函数创建对象。实例对象的构造类都是Object,不方便区分是哪一类。
构造函数:
函数名大驼峰命名法,函数内部没有new,没有返回值,this代指当前对象,通过new的方式创建对象。方便区分是某类的对象,可以用instanceof检测
构造函数与实例对象的区别
function Person(name, age, sex){ this.name = name; this.age = age; this.sex = sex; this.say = function(){ console.log("say...."); }; }var p = new Person("aa", 13, "男"); //构造函数与实例对象之间的关系 //实例对象是通过构造函数创建出来的 //console.dir打印对象结构 console.dir(p); //打印实例对象 console.dir(Person); //打印构造函数//constructor实例对象的构造器 指向的是Person 所以这个实例对象是通过Person来创建的 console.log(p.__proto__.constructor == Person.prototype.constructor); console.log(p.constructor == Person);
结论:
实例对象是通过构造函数创建的 可以通过 实例对象.构造器 == 构造函数名 来判断对象是不是这个构造函数创建的 对象 instanceof 构造函数名 一般使用这种方式
原型
javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用每一个构造函数都有一个属性叫做原型。这个属性非常有用:为一个特定类声明通用的变量或者函数。
你不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。
prototype 既是属性也是对象。
每个函数都有一个 prototype 属性,被称为原型对象,原型对象中的属性和方法可以通过实例对象访问。
每个实例对象都有一个 __ proto__ 属性,指向该实例对象的构造函数。
可以根据这两个属性来判断该元素是函数还是对象。
原型的引入
//构造函数 构造函数名Personfunction Person(name, age){this.name = name;this.age = age;this.say = function(){console.log("say");};}//得到一个实例对象var p1 = new Person("aa", 34);var p2 = new Person("bb", 45);//这两个方法是否是同一个方法? 不是同一个方法p1.say();p2.say();
结论:
通过上述方式创建的对象,分别拥有自己的属性和方法。如果多个实例对象拥有同样的方法,采用这种方式比较浪费空间,可以采用原型对象的方式,将共有的属性和方法存储在原型对象中,实现空间共享,节省空间。
原型的作用
数据共享
在构造函数中定义的属性和方法,在实例对象的时候,实例对象的属性和方法都是在自己的空间中存在的。如果实例化多个对象,那么这些属性和方法都会存储在单独的空间,为了节省内存空间,我们会把对象共有的属性或方法写在原型对象中,实现节省内存空间。
改变this指向
原型对象中的this指向为实例对象,指向可以改变。
构造函数、实例、原型之间的关系
Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。
这个对象的所有属性和方法,都会被构造函数的实例继承。
这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。
这时所有实例的 type 属性和 sayName() 方法,
其实都是同一个内存地址,指向 prototype 对象,因此就提高了运行效率。
任何函数都具有一个 prototype 属性,该属性是一个对象。
通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针proto。
总结:
任何函数都具有一个 prototype 属性,该属性是一个对象
构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数
通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针
proto
所有实例都直接或间接继承了原型对象的成员
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkotGMpW-1577673827666)(/home/yujing/.config/Typora/typora-user-images/image-1119103004205.png)]
通过原型对象添加方法
构造函数.prototype.属性 = 值;
构造函数.prototype.方法 = 值;
通过原型对象添加属性可以简写为:
构造函数.prototype = {
手动加构造器
}
//构造函数 构造函数名Personfunction Person(name, age){this.name = name;this.age = age;}//使用原型添加方法Person.prototype.say = function(){console.log("say....");};//判断两个方法是否是同一个方法console.log(p1.say == p2.say); //true
结论:
使用原型对象创建属性和方法,在实例化对象中看不到这个属性或方法。
原型对象
实例对象中有一个__proto__的属性,就是原型,也是一个对象,这个属性是给浏览器使用,不是标准属性,__proto__可以叫原型对象
构造函数中有一个prototype的属性,就是原型,也是一个对象,这个是标准属性,这个属性是程序使用的。prototype可以叫原型对象
实例对象中的__proto__属性与构造函数中的prototype属性相等
实例对象是通过构造函数创建出来的,构造函数中有prototype原型对象
实例对象__proto__指向了构造函数中的原型对象
通过原型添加属性和方法
Person.prototype.classid = "220";Person.prototype.eat = function(){console.log("吃盒饭.....");};Person.prototype.study = function(){console.log("吃饭睡觉打豆豆,就是不学习,因为我不学就会");};
以上代码可以简写:
需要注意的是,需要手动添加 constructor 构造器
//使用原型添加属性和方法Person.prototype = {//手动添加构造器constructor: Person,classid: "220",eat: function(){console.log("吃饭的方法");}};
总结:实例对象与原型对象的关系
构造函数可以实例化对象。
构造函数中有一个属性叫prototype,是构造函数的原型对象。
构造函数的原型对象(prototype)中有一个constructor构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数。
实例对象的原型对象(proto)指向的是该构造函数的原型对象。
实例对象属性与原型属性重名问题
当访问实例对象的某个属性的时候,首先会在实例对象的构造函数中寻找,找到了就直接使用,找不到就会按照原型链向原型对象中寻找。如果找不到,属性会返回 undefined 方法会返回 not a function
通过实例对象可以改变原型对象中的属性值吗?
不可以。如果想改变原型对象中属性的值,可以直接通过 原型对象.属性 = 值 的方式改变。
原型对象使用建议
私有成员(一般就是非函数成员)放到构造函数中
共享成员(一般就是函数)放到原型对象中
如果重置了 prototype 记得修正 constructor 的指向
可以为系统内置对象添加原型方法,相当于再改源码
系统内置对象的属性和方法可能不能满足需要,可以通过原型的方式加入属性和方法,为了方便开发
为内置对象的原型添加属性和方法,那么这个内置对象的实例对象就可以直接使用
String.prototype.myReverse=function () {for(var i=this.length-1;i>=0;i--){console.log(this[i]);} }; var str="abcdefg"; str.myReverse();
构造函数与实例对象的关系
实例对象是由构造函数所创建的;
实例对象中的 proto 中的 constructor指向构造函数
构造函数中的 constructor存储构造函数本身
验证一个实例对象是否是由某个构造函数产生的
对象 instanceof 构造方法 判断 建议用这个
对象.constructor = 构造方法名 返回布尔值
原型中的方法是可以互相访问的
function Animal(name,age) {this.name=name;this.age=age; } //原型中添加方法 Animal.prototype.eat=function () {console.log("动物吃东西");this.play(); }; Animal.prototype.play=function () {console.log("玩球");this.sleep(); }; Animal.prototype.sleep=function () {console.log("睡觉了");}
注意:
实例化对象与原型属性重名时,先寻找对象本身的属性,对象本身没有时再采用原型的属性,都没有时属性返回undefined,方法返回not a function
function Person(age,sex) {this.age=age;//年龄this.sex=sex;this.eat=function () {console.log("构造函数中的吃"); }; } Person.prototype.sex="女"; Person.prototype.eat=function () { console.log("原型对象中的吃"); }; var per=new Person(20,"男"); console.log(per.sex); //男 per.eat();//构造函数中的吃
原型链
原型链:是一种关系,实例对象和原型对象之间的关系,他们的关系 是通过原型 __ proto__ 来联系的。
每个构造函数都有一个 prototype 属性,每个实例对象都有一个 __ proto__ 属性,而 __ proto__ 属性指向构造函数的 prototype 属性。按照__ proto__ 寻找原型链的构造函数,会发现实例对象的顶端是 Object ,再向上寻找__ proto__ 会返回null。
//构造函数 function Person(name,age) { //属性 this.name=name; this.age=age; //在构造函数中的方法 this.eat=function () { console.log("吃吃吃"); }; } //添加共享的属性 Person.prototype.sex="男"; //添加共享的方法 Person.prototype.sayHi=function () { console.log("您好啊,"); };//实例化对象,并初始化 var per=new Person("小明",20); per.sayHi(); //如果想要使用一些属性和方法,并且属性的值在每个对象中都是一样的,方法在每个对象中的操作也都是一 样,那么,为了共享数据,节省内存空间,是可以把属性和方法通过原型的方式进行赋值console.dir(per);//实例对象的结构 console.dir(Person);//构造函数的结构//实例对象的原型__proto__和构造函数的原型prototype指向是相同的//实例对象中的__proto__原型指向的是构造函数中的原型prototype console.log(per.__proto__==Person.prototype); //实例对象中__proto__是原型,浏览器使用的 //构造函数中的prototype是原型,程序员使用的
原型的指向是可以改变的
实例对象的原型 __ proto __ 指向的是该对象所在的构造函数的原型对象。如果构造函数的原型对象 prototype 指向发生了改变,实例对象的原型 __ proto__ 指向也会发生改变。实例对象和原型对象之间是通过 __ proto__ 原先来联系的,这个关系就是原型链。
//人的构造函数 function Person(age) { this.age=10; } //人的原型对象方法 Person.prototype.eat=function () { console.log("人的吃"); }; //学生的构造函数 function Student() {} Student.prototype.sayHi=function () { console.log("嗨,小苏你好帅哦"); }; //学生的原型,指向了一个人的实例对象 Student.prototype=new Person(10); //改变了原型的指向var stu=new Student(); stu.eat(); stu.sayHi();
原型的最终指向问题
Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。
这个对象的所有属性和方法,都会被构造函数的实例继承。
这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。
prototype是对象,所以prototype这个对象中也有proto,指向了哪儿里?(对象中proto指 向的都是构造函数的prototype) 所以prototype这个对象中的proto指向的应该是某个构造函数的原型prototype
function Person() {} Person.prototype.eat=function () {console.log("吃东西"); };var per=new Person(); console.dir(per); console.dir(Person); //per实例对象的__proto__------->Person.prototype的__proto__---->Object.prototype的 __proto__是nullconsole.log(per.__proto__==Person.prototype); console.log(per.__proto__.__proto__==Person.prototype.__proto__); console.log(Person.prototype.__proto__==Object.prototype); console.log(Object.prototype.__proto__);
原型指向改变如何添加方法
如果原型的指向发生改变,那么应该在原型改变指向之后再添加原型方法。
//人的构造函数 function Person(age) {this.age=age; } //人的原型中添加方法 Person.prototype.eat=function () {console.log("正在吃东西"); }; //学生构造函数 function Student(sex) {this.sex=sex; } //改变了原型对象的指向 Student.prototype=new Person(10);//学生的原型中添加方法----先在原型中添加方法 Student.prototype.sayHi=function () {console.log("哈喽哈喽"); }; var stu=new Student("男"); stu.eat(); stu.sayHi();console.dir(stu);
继承
JS 不是一门面向对象的语言,它是一门基于对象的语言。我们学习 JS 的面向对象,是英文面向对象的思想适合人的想法,编程会更加方便,也利于后期的维护。
继承:首先继承是一种关系。
可以通过构造函数模拟类,然后通过改变原型指向来实现继承。继承也是为了实现数据共享。
缺陷:通过改变原型指向实现的继承,直接初始化了属性,继承过来的属性的值都是一样的。为了解决这一个问题,我们可以使用 call 函数。(指构造函数中的属性值不能改变)
继承的时候,可以不改变原型的指向,直接调用父级的构造函数的方式来为属性赋值就可以了。借用构造函数,把要继承的父级的构造函数拿过来,使用一下就可以了。
要借用的构造函数.call(要绑定函数的对象 [, 函数的参数1] [, 函数的参数2…] )
缺陷:父级中的方法不能继承。(指原型对象中的成员不能继承)
所以,为了完美实现继承,我们采用 原型继承 + 借用构造函数 来实现继承。
原型继承 + 借用构造函数 来实现继承
function Person(name,age,sex) { this.name=name; this.age=age; this.sex=sex; } Person.prototype.sayHi=function () { console.log("哈喽"); }; function Student(name,age,sex,score) { //借用构造函数:属性值重复的问题 Person.call(this,name,age,sex); this.score=score; } //改变原型指向----继承 Student.prototype=new Person();//不传值 //改变原型指向后添加方法 Student.prototype.eat=function () { console.log("吃东西"); }; var stu=new Student("小黑",20,"男","100分"); console.log(stu.name,stu.age,stu.sex,stu.score); stu.sayHi(); stu.eat(); var stu2=new Student("小黑黑",200,"男人","1010分"); console.log(stu2.name,stu2.age,stu2.sex,stu2.score); stu2.sayHi(); stu2.eat();
拷贝继承
把一个对象的竖向或方法通过遍历对象 直接复制到另一个对象中。
function Person() {} Person.prototype.age=10; Person.prototype.sex="男"; Person.prototype.height=100; Person.prototype.play=function () { console.log("玩的好开心"); }; var obj2={}; //Person的构造中有原型prototype,prototype就是一个对象,那么里面,age,sex,height,play都是 该对象中的属性或者方法 for(var key in Person.prototype){ obj2[key]=Person.prototype[key]; } console.dir(obj2); obj2.play();
总结继承:
原型继承:改变原型的指向
借用构造函数继承:主要解决属性值不可改变的问题
原型继承 + 借用函数继承,既能解决属性的问题,又能解决方法继承的问题。
拷贝继承:就是把对象中需要共享的属性或方法,通过遍历的方式复制到另一个对象中。
函数
函数的声明方式
(1)函数声明的方式
function 函数名 () {}
(2)函数表达式
function () {}
函数声明和函数表达式的区别:
函数声明如果放在 if… else 分支结构中,在IE8 中会出现问题
//函数声明方式if(true){ function f1() { console.log("真区间函数"); } }else{function f1() {console.log("假区间函数"); } } f1();//IE8 下返回 ‘假区间函数’
//函数表达式方式var f2; if(true){ f2=function () { console.log("函数表达式--真区间"); }; }else{ f2=function () { console.log("函数表达式--假区间"); }; } f2();//所有浏览器都返回 "函数表达式--真区间"
函数中 this 指向
//普通函数中this function f1() { console.log(this); } f1(); //定时器中的this setInterval(function () { console.log(this); },1000);//构造函数中this function Person() { console.log(this); //对象方法中this this.sayHi=function () { console.log(this); }; } //原型中的方法中this Person.prototype.eat=function () { console.log(this); }; var per=new Person(); console.log(per); per.sayHi(); per.eat();//严格模式 "use strict";function f1() { console.log(this);//window } f1();
函数的不同调用方式
//普通函数 function f1() { console.log("普通函数"); } f1(); //构造函数---通过new 来调用,创建对象 function F1() { console.log("我是构造函数"); } var f=new F1();//对象的方法 function Person() { this.play=function () { console.log("玩玩玩"); }; } var per=new Person(); per.play();
函数是对象,对象不一定是函数
对象中有proto原型,函数中有prototype原型,如果一个结构里既有prototype,又有proto, 说明是函数,也是对象
//对象中有__proto__原型,是对象 //函数中有prototype原型,是对象 function F1() { } //函数中有prototype,也有__proto__ console.dir(F1);//Math是对象 但不是函数没有prototype console.dir(Math);//所有的函数实际上都是Function的构造函数创建出来的实例对象 var f1=new Function("num1","num2","return num1+num2"); console.log(f1(1,2)); console.log(f1.__proto__==Function.prototype);console.dir(f1); console.dir(Function);
apply和call方法的使用
apply的使用语法
函数名字.apply(调用该函数的对象,[参数1,参数2,…]);
方法名字.apply(对象,[参数1,参数2,…]);
call的使用语法
函数名字.call(对象,参数1,参数2,…);
方法名字.call(对象,参数1,参数2,…);
作用:改变this的指向
不同的地方:参数传递的方式是不一样的,apply参数是数组 ,call是参数列,逗号分隔
只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么就可以使用apply或者是call的方法改变this的指向
注意:
apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是 默认的window
//调用函数 function f1(x,y) { console.log("结果是:"+(x+y)+this); return "test"; }f1(10,20);//函数的调用f1.apply(); f1.call();f1.apply(null); f1.call(null); //apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是 默认的window f1.apply(null,[100,200]); f1.call(null,100,200); var result1=f1.apply(null,[10,20]); var result2=f1.call(null,10,20); console.log(result1);console.log(result2);
bind() 复制
使用的语法:
函数名字.bind(对象,参数1,参数2,…);---->返回值是复制之后的这个函数
方法名字.bind(对象,参数1,参数2,…);---->返回值是复制之后的这个方法
复制了一份的时候,把参数传入到了f1函数中,x== >10,y==>20,null就是this,默认就是window bind方法是复制的意思,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去apply和call是调用的时候改变this指向 bind方法,是复制的时候,改变了this的指向
function f1(x, y) {console.log((x + y) + ":=====>" + this.age); } function Person() {this.age = 1000; } Person.prototype.eat = function () {console.log("这个是吃"); }; var per = new Person(); var ff = f1.bind(per, 10, 20); ff();
函数中的几个成员
name:函数的名字,name 属性是只读的,不能修改
arguments:实参 arguments[i] 实参的值 arguments.length 实参的个数
length:形参的个数
caller:函数的调用者
闭包
闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这 句话暂时不严谨)
闭包的模式:函数模式的闭包,对象模式的闭包
闭包的作用:缓存数据,延长作用域链
**闭包的优点和缺点:**缓存数据
//函数模式的闭包:在一个函数中有一个函数function f1() { var num=10; //函数的声明 function f2() {console.log(num); } //函数调用 f2(); } f1();//10
//对象模式的闭包:函数中有一个对象 function f3() { var num=10; var obj={ age:num }; console.log(obj.age);//10 } f3();
//普通的函数 function f1() {var num = 10;num++;return num; } console.log(f1()); console.log(f1()); console.log(f1()); //函数模式的闭包 function f2() {var num = 10;return function () { num++; return num;}} var ff = f2(); console.log(ff()); //11console.log(ff()); //12console.log(ff()); //13
总结:
如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置 闭包的作用:缓存数据.优点也是缺陷,没有及时的释放 局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放 闭包后,里面的局部变量的使用作用域链就会被延长
沙箱
环境,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世 界。
var num=10; console.log(num+10);//沙箱---小环境 (function () {var num=10;console.log(num); })();//沙箱---小环境 (function () {var num=20;console.log(num+10); }());var num=100; (function () {var num=10;console.log(num);//10 }());console.log(num);//100
递归
函数中调用函数自己,此时就是递归,递归一定要有结束的条件。
//递归实现:求n个数字的和 n=5---> 5+4+3+2+1 //函数的声明 function getSum(x) { if(x==1){return 1; } return x+getSum(x-1); } //函数的调用 console.log(getSum(5));
//递归案例:求斐波那契数列function getFib(x) {if(x==1||x==2){ return 1}return getFib(x-1)+getFib(x-2); } console.log(getFib(12));
浅拷贝
拷贝就是复制,就相当于把一个对象中的所有的内容,复制一份给另一个对象,直接复制,或者说,就是把一个 对象的地址给了另一个对象,他们指向相同,两个对象之间有共同的属性或者方法,都可以使用
var obj1={age:10,sex:"男",car:["benchi","hafu","baoma","aodi"] }; //另一个对象 var obj2={}; //写一个函数,作用:把一个对象的属性复制到另一个对象中,浅拷贝 //把a对象中的所有的属性复制到对象b中 function extend(a,b) {for(var key in a){ b[key]=a[key];} } extend(obj1,obj2); console.dir(obj2); console.dir(obj1);
深拷贝
拷贝还是复制,深:把一个对象中所有的属性或者方法,一个一个的找到.并且在另一个对象中开辟相应的空 间,一个一个的存储到另一个对象中。两者内存地址不同。
var obj1={age:10,sex:"男",car:["benchi","hafu","baoma","aodi"],dog:{ name:"大黄", age:5, color:"黑白色"} };var obj2={};//空对象 //通过函数实现,把对象a中的所有的数据深拷贝到对象b中 function extend(a,b) {for(var key in a){ //先获取a对象中每个属性的值 var item=a[key]; //判断这个属性的值是不是数组 if(item instanceof Array){//如果是数组,那么在b对象中添加一个新的属性,并且这个属性值也是数组b[key]=[];//调用这个方法,把a对象中这个数组的属性值一个一个的复制到b对象的这个数组属性中extend(item,b[key]); }else if(item instanceof Object){//判断这个值是不是对象类型的//如果是对象类型的,那么在b对象中添加一个属性,是一个空对象 b[key]={};//再次调用这个函数,把a对象中的属性对象的值一个一个的复制到b对象的这个属性对象中extend(item,b[key]);}else{//如果值是普通的数据,直接复制到b对象的这个属性中b[key]=item;} } }extend(obj1,obj2); console.dir(obj1); console.dir(obj2);
浅拷贝与深拷贝的区别:
1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
2.深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
正则表达式
也叫规则表达式,按照一定的规则组成的一个表达式,这个表达式的作用主要是匹配字符串的,
正则表达式的作用:匹配字符串的
在大多数编程语言中都可以使用 正则表达式的组成:是由元字符或者是限定符组成的一个式子
元字符
. 表示的是:除了\n(换行)以外的任意的一个字符 "fdsfs238" [] 表示的是:范围, [0-9] 表示的是0到9之间的任意的一个数字, "789" [0-9] [1-7] 表示的是1到7之间的任意的一个数字 [a-z] 表示的是:所有的小写的字母中的任意的一个 [A-Z] 表示的是:所有的大写的字母中的任意的一个 [a-zA-Z] 表示的是:所有的字母的任意的一个 [0-9a-zA-Z] 表示的是: 所有的数字或者是字母中的一个 [] 另一个函数: 把正则表达式中元字符的意义干掉 [.] 就是一个. | 或者 [0-9]|[a-z] 表示的是要么是一个数字,要么是一个小写的字母 () 分组 提升优先级 [0-9]|([a-z])|[A-Z] ([0-9])([1-5])([a-z]) 三组, 从左边开始计算
都是元字符,但是也可以叫限定符,下面的这些* 表示的是:前面的表达式出现了0次到多次 [a-z][0-9]* 小写字母中的任意一个 后面是要么是没有数字的,要么是多个数字的 "fdsfs3223323" + 表示的是:前面的表达式出现了1次到多次 [a-z][9]+ 小写字母一个后面少一个9,或者多个9 "fesfewww9fefds"? 表示的是:前面的表达式出现了0次到1次,少是0次,多1次 ,另一个含义:阻止贪婪模式 [4][a-z]? "1231234ij" 限定符:限定前面的表达式出现的次数{} 更加的明确前面的表达式出现的次数 {0,} 表示的是前面的表达式出现了0次到多次,和 *一样的 {1,} 表示的是前面的表达式出现了1次到多次,和 +一样的 {0,1} 表示的是前面的表达式出现了0次到1次,和 ?一样的 {5,10} 表示的是前面的表达式出现了5次到10次 {4} 前面的表达式出现了4次方括号用于查找某个范围内的字符:^ 表示的是以什么开始,或者是取非(取反) ^[0-9] 以数字开头^[a-z] 以小写字母开始 [^0-9] 取反,非数字 [^a-z] 非小写字母 [^0-9a-zA-Z_]$ 表示的是以什么结束 [0-9][a-z]$ 必须以小写字母结束 ^[0-9][a-z]$ 相当于是严格模式 "3f2432e" "4f" 修正符\元字符\d 数字中的任意一个, \D 非数字中的一个\s 空白符中的一个\S 非空白符\w 非特殊符号 \W 特殊符号\b 匹配单词边界\uxxxx 查找以十六进制xxxx规定的Unicode字符修饰符g 全局匹配i 不区分大小写m 多行匹配x 忽略正则表达式中的空白U 拒绝贪婪.* 贪婪模式.*? 非贪婪模式反向引用当我们匹配一个字符串的时候,可能会需要获取原字符串中的内容,此时我们可以这样做//源字符串-10-14//正则(\d{4})-(\d{2})-(\d{2})//需要转换成 10/14/的格式,就用到反向表达式$2/$3/$1在正则中被分组的字符,我们可以通过$1 $2 $3...来捕获,如果需要引用原字符串的内容,只需要引用对应的 $1 $2 $3...即可。
创建正则表达式对象
//1.通过构造函数创建对象 var reg=new RegExp(/\d{5}/); //字符串var str="我的电话是10086"; //调用方法验证字符串是否匹配 var flag=reg.test(str); console.log(flag);//对象创建完毕--var reg=new RegExp(/\d{5}/);//调用方法验证字符串是否匹配 var flag=reg.test("我的电话是10086");console.log(flag);//2.字面量的方式创建正则表达式对象var reg=/\d{1,5}/;var flag=reg.test("小苏的幸运数字:888"); console.log(flag);
身份证号 /^\d{17}(\d|[a-z])$/
手机号 /^\d{11}$/
qq号 /^\d{5,11}$/
固话 /^\d{3,4}[-]\d{7,8}$/
邮箱 /^\w+@\w+( \ .\w+){1,3}$/
日期 /\d{4}-\d{1,2}-\d{1,2}/
表单验证思路:
利用失去焦点事件onblur,(同时定义一个布尔值作为返回值,用作最后整体提交),判断如果值为空则提示输入值,如果有值则判断格式是否正确,格式错误返回false,格式正确返回true,最后在提交表单时整体验证只有所有都为true才可以提交。
正则表达式中的方法
search()
search() 用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的字符串,并返回起始位置。
参数:正则或要查询的字符。
返回值:查询字符的起始位置。
使用正则搜索字符串,不区分大小写:
var str = "hello world";var n = search(/ld/i);console.log(n);
使用字符搜索字符串,不区分大小写:
var str = "hello world";var n = search("ld");console.log(n);
repalce()
repalce()用指定字符替换其他字符,或替换与正则匹配的字符。
参数:要修改的字符/匹配的正则,要替换的字符。
返回值:修改后的字符串。
var ss = "this is a good day";var nn = ss.replace("good","bad");//var nn = ss.replace(/good/i,"bad");console.log(nn);//this is a bad day
test()
test()检测字符串是不是匹配某个模式,如果有匹配文本则返回true,否则返回false。
redExp.test();
var res = /e/.test("the best thing in the life are free");console.log(res);//true
exec()
检索字符串中正则的匹配。
redExp.exec();
/e/.exec("this is the best thing , free");