一、JavaScript面向对象
1. 面向对象编程介绍
1.1 两大编程思想
- 面向对象
- 面向过程
1.2 面向过程编程
面向过程 编程,即 POP(Process-oriented programming)。面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。
1.3 面向对象编程
面向对象 编程,即 OOP(Object Oriented Programming) 面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。
在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工。 面向对象编程具有灵活、代码可复用、容易维护和开发的优点,更适合多人合作的大型软件项目。
面向对象的特性:
- 封装性
- 继承性
- 多态性
1.4 面向过程和面向对象的对比
1.4.1 面向过程
- 优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程。
- 缺点:没有面向对象易维护、易复用、易扩展。
1.4.2 面向对象
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
- 缺点:性能比面向过程低。
2. ES6中的类和对象
2.1 对象
现实生活中:万物皆对象,对象是 一个具体的事物,看得见摸得着的实物。例如,一本书、一辆汽车、一个人可以是“对象”,一个数据库、一张网页、一个与远程服务器的连接也可以是“对象”。
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的:
- 属性:事物的 特征,在对象中用 属性 来表示(常用名词)
- 方法:事物的 行为,在对象中用 方法 来表示(常用动词)
2.2 类 class
在 ES6 中新增加了类的概念,可以使用 class 关键字声明—个类,之后以这个类来实例化对象。
- 类 抽象了对象的公共部分,它泛指某一大类(class)
- 对象 特指某一个,通过类实例化一个具体的对象
面向对象的思维特点:
- 抽取(抽象)对象共用的属性和行为组织(封装)成—个类(模板)
- 对类进行实例化,获取类的对象
2.3 创建类和对象
语法:
class ClassName {
// class body
}
创建实例:
let obj = new ClassName();
类必须使用 new 实例化对象
2.4 类 constructor 构造函数
constructor() 方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过new命令生成对象实例时,自动调用该方法。如果没有显示定义,类内部会自动给我们创建一个 constructor()。
// 创建一个学生类
class Student {
constructor(uname, age, major) {
this.uname = uname;
this.age = age;
this.major = major;
}
}
// 类的实例化--创建对象
let peter = new Student("Peter", 21, "CS");
console.log(peter.uname); // Peter
注意:
- 通过
class关键字创建类, 类名我们还是习惯性定义首字母大写 - 类里面有个
constructor函数,可以接受传递过来的参数,同时返回实例对象 constructor函数 只要new生成实例时,就会自动调用这个函数, 如果我们不写这个函数,类也会自动生成这个函数- 生成实例
new不能省略 - 最后注意语法规范, 创建类:类名后面不要加小括号。生成实例:类名后面加小括号, 构造函数不需要加
function
2.5 类中添加方法
class Student {
// 类的共有属性放到 constructor 中
constructor(uname, age, major) {
this.uname = uname;
this.age = age;
this.major = major;
}
// 类中添加方法
sing() {
console.log(this.uname + "会唱歌");
}
}
// 创建实例
let peter = new Student("Peter", 18, "化学");
peter.sing(); // Peter会唱歌
(1)类里面所有的函数不需要写 function
(2)多个函数方法之间不需要添加逗号
3. 类继承extends和super关键字
3.1 类的继承
继承:子类可以继承父类的一些属性和方法
class Son extends Father {
// class body
}
在继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的,如果没有,就去查找父类有没有这个方法,有就执行父类的(就近原则)
3.2 super关键字
super关键字:用于访问和调用对象父亲上的函数,可以调用父类的构造函数,也可以调用父类的普通函数
class Person {
constructor (uname, age) {
this.uname =uname;
this.age = age;
}
shuchu(){
return '我的名字是'+this.uname+',年龄'+this.age+'岁'
}
}
class Student extends Person {
constructor (uname, age, major) {
// super 将子类的参数传递给父类构造函数,减少代码量
super(uname, age);
// 子类可以有自己独有的属性
this.major = major;
}
shuchu(){
console.log(super.shuchu())
}
}
let rick = new Student("Rick", 22, "数学");
rick.shuchu()
//因为shuchu这个函数的参数都是父亲Person的实例的属性,他们的this都指向父亲的实例,无法使用子类的参数
//所以我们要给父亲传参,调用super类
3.3 super必须放在子类this之前
class Father {
constructor(x, y){
this.x = x
this.y = y
}
sum(){
console.log(this.x + this.y)
}
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extents Father{
constructor(x, y){
// 利用super 调用父类的构造函数
// super必须在子类 this之前调用
super(x, y)
this.x = x
this.y = y
}
subtract(){
console.log(this.x - this.y)
}
}
var son = new Son(8, 2)
son.subtract() // 6
son.sum() // 10
4. 使用类的注意点
- 在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
- 类里面的共有属性和方法一定要加 this 使用
- 类里面的this指向问题:constructor 里面的this指向实例对象,方法里面的this指向这个方法的调用者
案例分析如下:
var that;
var _that;
class Star {
constructor (uname, age) {
that = this;
this.uname = uname;
this.age = age;
// btn按钮调用sing方法
this.btn = document.querySelector("button");
this.btn.onclick = this.sing;
// constructor 里面的this 指向的是 创建的实例对象
console.log("constructor: ", this);
}
sing() {
// 这个sing方法里面的 this 指向的是 btn 这个按钮,因为这个按钮调用了这个函数
console.log("sing:", this); // button
console.log(that.uname); // that里面存储的是constructor里面的this
}
dance() {
// 这个dance里面的this 指向的是实例对象rick,因为rick调用了这个函数
_that = this
console.log("dance:", this);
}
}
let rick = new Star("Rick", 20);
rick.dance();
console.log(that === rick) // true
console.log(_that === rick) // true
二、构造函数和原型
1. 构造函数和原型
1.1 概述
在典型的OOP的语言中(如Java),都存在类的概念,类就是对象的模版,对象就是类的实例,但在ES6之前,JS中并没有引入类的概念。
在ES6之前,对象不是基于类创建的,而是用一种称为构建函数的特殊函数来定义对象和它们的特征。
创建对象可以通过以下三种方式:
1.对象字面量
2.new Object()
3.自定义构造函数
<script>
// 1.利用 new Object() 创建对象
var obj1 = new Object()
// 2.利用 对象字面量
var obj2 = {}
// 3.利用构造函数
function Star(uname, age){
this.uname = uname
this.age = age
this.sing = function(){
console.log('I can sing')
}
}
var ldh = new Star('刘德华',40)
console.log(ldh)
ldh.sing() // I can sing
</script>
1.2 构造函数
构造函数是一种特殊的函数,主要是用来初始化对象,即为对象成员变量赋初始值,它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在JS中,使用构造函数时要注意以下两点:
①构造函数用于创建某一类对象,其首字母要大写
②构造函数要和new一起使用才有意义
new在执行时会做四件事情:
① 在内存中创建一个新的空对象
② 让this指向这个新对象
③ 执行构造函数里面的代码,给这个新对象添加属性和方法
④ 返回这个新对象(所以构造函数里面不需要return)
JavaScript的构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加。通过这两种方式添加的成员,就分别称为
静态成员和实例成员。
- 静态成员:在构造函数本身上添加的成员称为
静态成员,只能由构造函数本身来访问- 实例成员:在构造函数内部创建的对象成员称为
实例成员,只能由实例化的对象来访问
1.3 构造函数的问题
构造函数方法很好用,但是存在浪费内存的问题
//比较的是内存地址,两个实例对象开辟的内存地址不同,所以返回false
console.log( ldh.sing === zxy.sing ) // false
我们希望所有的对象使用同一个函数,这样比较节省内存,那么要怎么做呢?
1.4 构造函数原型 prototype
构造函数通过原型分配的函数是所有对象所共享的。
JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。
1.原型是什么?
一个对象,我们也称prototype为原型对象。
2.原型的作用是什么?
共享方法。
1.5 对象原型 __proto__
对象都会有一个属性 __proto__ , 指向构造函数的 prototype原型对象,之所以我们对象可以使用prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在。
__proto__对象原型和原型对象 prototype 是等价的。__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype。
1.6 constructor 构造函数
对象原型(__proto__)和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为它指回构造函数本身。
constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
<script>
function Star(uname, age){
this.uname =uname;
this.age =age;
}
Star.prototype.sing = function(){
console.log('我会唱歌');
}
var ldh = new Star('刘德华',18);
var zxy = new Star('张学友',19);
console.log(Star.prototype);
console.log(ldh.__proto__);
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);
</script>
<script>
function Star(uname, age){
this.uname =uname;
this.age =age;
}
// 很多情况下,需要手动的利用constructor这个属性指回 原来的构造函数
Star.prototype = {
constructor: Star,// 不加这句话结果是图一,加上这句话结果是图二
sing: function(){
console.log('我会唱歌')
}
}
var ldh = new Star('刘德华',18);
var zxy = new Star('张学友',19);
console.log(Star.prototype);
console.log(ldh.__proto__);
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);
</script>
图一:
图二:
如果修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数。
1.7 构造函数、实例、原型对象三者之间的关系
1.8 原型链
<script>
function Star(uname, age){
this.uname =uname;
this.age =age;
}
Star.prototype.sing = function(){
console.log('我会唱歌')
}
var ldh = new Star('刘德华',18);
// 1.只要是对象就有 __proto__ 原型,指向原型对象
console.log(Star.prototype);
console.log(Star.prototype.__proto__ === Object.prototype);
// 2.我们Star原型对象里面的__proto__原型指向的是Object.prototype
console.log(Object.prototype.__proto__)
// 3.我们Object.prototype原型对象里面的__proto__ 指向 null
</script>
- 构造函数有原型对象 prototype 。
- 构造函数原型对象 prototype 里面有 constructor 指向构造函数本身。
- 构造函数可以通过原型对象添加方法。
- 构造函数创建的实例对象有
__proto__原型指向构造函数的原型对象。
1.9 JavaScript的成员查找机制(规则)
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 __proto__ 指向的 prototype原型对象)。
③ 如果还没有就查找原型对象的原型(Object的原型对象)。
④ 以此类推一直找到Object为止(null)。
⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
1.10 原型对象this指向
1.11 扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能。
注意:数组和字符串内置对象不能给原型对象覆盖操作Array.prototype = {},只能是 Array.prototype.xxx = function(){} 的方式。
2. 继承
ES6之前并没有提供extends继承,我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
2.1 call()
调用这个函数,并且修改函数运行时的this指向。
// call 方法
function fn(){
console.log('drinking')
console.log(this) // 指向window
}
var obj = {
name: 'tony'
}
// 1. call() 可以调用函数
fn.call()
// 2. call()改变函数的this指向,此时这个函数的this就指向了obj这个对象
fn.call(obj)
2.2 借助构造函数继承父类属性
核心原理:通过call()把父类的this指向子类的this,这样就可以实现子类继承父类的属性。
function Father(uname, age){
// 这里的this指向父类构造函数的对象实例
this.uname = uname
this.age = age
}
Father.prototype.money = function(){
console.log('money')
}
// 2.3 借助原型对象继承父类方法
Son.prototype = new Father()
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son
Son.prototype.exam = function(){
console.log('exam')
}
function Son(uname, age, sex){
// 这里的this指向子类构造函数的对象实例
Father.call(this, uname, age)
this.sex = sex
}
var s = new Son('xiaoxiao', 16, '男')
console.log(s.uname) // xiaoxiao
console.log(s)
2.3 借助原型对象继承父类方法
正确方法在2.2代码中
// 下面这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = Father.prototype
// 这是子构造函数单独所有的方法
Son.prototype.exam = function(){
console.log('exam')
}
console.log(Father.prototype) // Father也有exam方法
3. 类的本质
1. class的本质还是function
- 类有原型对象 prototype
- 类对象 prototype 里面有 constructor 指向类本身。
- 类可以通过原型对象添加方法。
- 类创建的实例对象有
__proto__原型指向类的prototype原型对象。
2. ES6的类绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
ES6的类其实就是语法糖。(语法糖就是一种便捷写法,简单理解,有两种方法实现同样的功能,但其中一种更清晰、方便,这个方法就是语法糖。)
三、ES5新增方法概述
ES5中新增的一些方法,可以很方便的操作数组或字符串,这些方法包括:
- 数组方法
- 字符串方法
- 对象方法
1.数组方法
迭代(遍历)方法:forEach()、map()、filter()、some()、every()
(1)array.forEach()
array.forEach(function(currentValue, index, arr))
- currentValue: 数组当前项的值
- index: 数组当前项的索引
- arr: 数组对象本身
(2)array.filter()
array.filter(function(currentValue, index, arr))
- filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,
主要用于筛选数组 注意:直接返回一个新数组- currentValue: 数组当前项的值
- index: 数组当前项的索引
- arr: 数组对象本身
var arr = [12, 88, 6, 28]
var newarr = arr.filter(function(item, index){
return item>20
})
console.log(newarr)
(3)array.some()
array.some(function(currentValue, index, arr))
- some()方法用于检测数组中的元素是否满足指定条件,通俗点查找数组中是否有满足条件的元素
注意:返回值是布尔值,如果找到这个元素返回true,如果查不到就返回false- 如果找到第一个满足条件的元素,则中止循环,不再继续查找
- currentValue: 数组当前项的值
- index: 数组当前项的索引
- arr: 数组对象本身
var arr = [12, 88, 6, 28]
var flag = arr.some(function(item, index){
return item>100
})
console.log(flag)
总结:
(1) filter 查找满足条件的元素,返回的是一个数组,而且是把所有满足条件的元素返回回来
(2) some 查找满足条件的元素是否存在,返回的是一个布尔值,如果查找到第一个满足条件的元素就终止循环
(3) 在forEach里面return不会中止迭代,在some里面遇到return true就是中止遍历,迭代效率更高。
2.字符串方法
(1) trim()
str.trim()
方法会从一个字符串的两端删除空白字符串。trim() 方法并不影响原字符串本身,它返回的是一个新的字符串。
(2) Object.defineProperty()
定义对象中新属性或修改原有的属性。
Object.defineProperty(obj, prop, descriptor)
- obj: 必需。目标对象
- prop: 必需。需定义或修改的属性的名字
- descriptor: 必需。目标属性所拥有的特性
var obj = {
id: '1',
name: '小米',
price: '1999'
}
// 1.以前的对象添加和修改属性的方式
// obj.num = 10
// 2.用Object.defineProperty()
Object.defineProperty(obj, 'num', {
value: 10
})
Object.defineProperty(obj, 'id', {
writable: false, // false不允许修改这个属性值
configurable:false, // false不允许被删除
})
obj.id = 2 // 无效
console.log(obj)
console.log(Object.keys(obj)) // ['id', 'name', 'price']
delete obj.id // 无效
console.log(obj)
(3) Object.keys()
用于获取对象自身所有的属性。
Object.keys(obj)
- 效果类似for…in
- 返回一个由属性名组成的数组
四、函数
1. 函数的定义和调用
1.1 函数的定义方式
(1)函数声明方式function关键字(命名函数)
(2)函数表达式(匿名函数)
(3)var fn = new Function('参数1', '参数2', '函数体')
- Function里面的参数必须是字符串格式
- 第三种方式执行效率低,不方便书写,很少使用
- 所有函数都是Function的实例(对象)
- 函数也属于对象
1.2 函数的调用方式
// 1. 普通函数
function fn() {
console.log('人生的巅峰');
}
// fn(); fn.call()
// 2. 对象的方法
var o = {
sayHi: function() {
console.log('人生的巅峰');
}
}
o.sayHi();
// 3. 构造函数
function Star() {};
new Star();
// 4. 绑定事件函数
// btn.onclick = function() {}; // 点击了按钮就可以调用这个函数
// 5. 定时器函数
// setInterval(function() {}, 1000); 这个函数是定时器自动1秒钟调用一次
// 6. 立即执行函数
(function() {
console.log('人生的巅峰');
})();
// 立即执行函数是自动调用
2. this
2.1 函数内 this 的指向
这些 this 的指向,是当我们调用函数的时候确定的。调用方式的不同决定了this的指向不同,一般指向我们的调用者。
// 函数的不同调用方式决定了this 的指向不同
// 1. 普通函数 this 指向window
function fn() {
console.log('普通函数的this' + this);
}
window.fn();
// 2. 对象的方法 this指向的是对象 o
var o = {
sayHi: function() {
console.log('对象方法的this:' + this);
}
}
o.sayHi();
// 3. 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
function Star() {};
Star.prototype.sing = function() { }
var ldh = new Star();
// 4. 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象
var btn = document.querySelector('button');
btn.onclick = function() {
console.log('绑定时间函数的this:' + this);
};
// 5. 定时器函数 this 指向的也是window
window.setTimeout(function() {
console.log('定时器的this:' + this);
}, 1000);
// 6. 立即执行函数 this还是指向window
(function() {
console.log('立即执行函数的this' + this);
})();
常用来改变this指向的三种方法为bind()、call()、apply()。
(1)call方法
call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向。
fun.call(thisArg, arg1, arg2)
call 的主要作用可以实现继承。
(2)apply方法
(3)bind方法
返回的是原函数改变this之后产生的新函数。
如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用bind。
2.2 call apply bind总结
相同点:都改变函数内部的this指向。
区别点:
- call 和 apply 会调用函数,并且改变函数内部this指向。
- call 和 apply 传递的参数不一样,call传递参数arg1,arg2 形式,apply必须数组形式[arg]。
- bind 不会调用函数,可以改变函数内部this指向。
主要应用场景:
- call经常做继承。
- apply经常跟数组有关系,比如借助于数学对象实现数组最大值最小值。
- bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向。
3. 严格模式
3.1 什么是严格模式
3.2 开启严格模式
3.3 严格模式中的变化
(1)变量规定
① 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,变量都必须先用var命令声明,然后再使用。
② 严禁删除已经声明变量。例如,delete x; 语法是错误的
(2)严格模式下this指向问题
① 以前在全局作用域函数中的this指向window对象。
② 严格模式下全局作用域中函数中的this是undefined。
③ 以前构造函数不加new也可以调用,当普通函数,this指向全局对象。
④ 严格模式下,如果构造函数不加 new 调用,this会报错。
⑤ new 实例化的构造函数指向创建的对象实例。
⑥ 定时器 this 还是指向 window。
⑦ 事件、对象还是指向调用者。
(3)函数变化
① 函数不能有重名的参数。
② 函数必须声明在顶层,新版本的JS会引入"块级作用域"(ES6已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。
4. 高阶函数
5. 闭包
5.1变量作用域
变量根据作用域的不同分为两种:全局变量和局部变量。
1.函数内部可以使用全局变量。
2.函数外部不可以使用局部变量。
3.当函数执行完毕,本作用域内的局部变量会销毁。
5.2什么是闭包
闭包指有权访问另一个函数作用域中变量的函数。
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量。
5.3闭包的作用
闭包的主要作用:延伸变量的作用范围
5.4闭包应用
(2)定时器中的闭包
(3)计算打车价格
思考:
5.5闭包总结
(1)闭包是什么? 闭包是一个函数(一个作用域可以访问另外一个函数的局部变量)。
(2)闭包的作用是什么?延伸变量的作用域。
6. 递归
6.1什么是递归
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。(简单理解:函数内部自己可以调用自己,这个函数就是递归函数)
递归函数的作用和循环效果一样。
由于递归很容易发生"栈溢出"错误,所以必须要加退出条件return。
利用递归求斐波那契数列:
6.2 浅拷贝和深拷贝
(1)浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
(2)深拷贝拷贝多层,每一级别的数据都会拷贝。
(3)Object.assign(target, ……sources) es6新增方法可以浅拷贝。
var obj = {
id: 1,
name: 'andy',
msg:{
age: 18
},
color:['pink', 'green']
}
var o = {}
for(var k in obj){ // k是属性名, obj[k]是属性值
o[k] = obj[k]
}
var t = {}
Object.assign(t, obj) //浅拷贝
console.log(t)
var deep = {}
// 封装函数(深拷贝)
function deepCopy(newObj, oldObj){
for(var k in oldObj){
// 判断我们的属性值属于哪种数据类型
// 1.获取属性值 oldObj[k]
var item = oldObj[k]
// 2.判断这个值是否是数组
if(item instanceof Array){
newObj[k] = []
deepCopy(newObj[k], item)
}else if(item instanceof Object){
// 3.判断这个值是否是对象
newObj[k] = {}
deepCopy(newObj[k], oldObj[k])
}else{
// 4.属于简单数据类型
newObj[k] = item
}
}
}
deepCopy(deep, obj)
console.log(deep)
deep.msg.age = 20
console.log(obj)
四、正则表达式
1.正则表达式概述
1.1什么是正则表达式
正则表达式是用于匹配字符串中字符组合的模式。在Javascript中,正则表达式也是对象。
1.2正则表达式的特点
2.正则表达式在Javascript中的使用
2.1创建正则表达式
在js中,有两种方式来创建正则表达式。
// 1.利用RegExp对象来创建正则表达式
var regexp = new RegExp(/123/)
// 2.利用字面量创建
var rg = /123/
// 正则表达式里面不需要加引号,不管是数字型还是字符串型
2.2测试正则表达式 test
test()正则对象方法,用于检测字符串是否符合该规则,该对象会返回true或false,其参数是测试字符串。
var rg = /123/ // 只要包含有123这个字符串返回的都是true
console.log(rg.test(123)) // true 判断正则表达式中是否出现了 123
console.log(rg.test('abc')) // false
console.log(rg.test(1)) // false
console.log(rg.test(4123)) // true
3.正则表达式中的特殊字符
3.1正则表达式的组成
一个正则表达式可以由简单的字符构成。比如 /adc/,也可以是简单和特殊字符的组合,比如/ab*c/,其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如 ^ 、$、 + 等。
3.2边界符
正则表达式中的边界符(位置符)用来提示字符所在的位置,主要有两个字符。
如果 ^ 和 $ 在一起,表示必须是精确匹配。
// 以123开头
var rg2 = /^123/
console.log(rg2.test(1234)) // true
console.log(rg2.test(4123)) // false
// 以123开头并且以123结尾(必须是123字符串才符合规范)
var rg2 = /^123$/
console.log(rg2.test(123)) // true
console.log(rg2.test(123123)) // false
3.3字符类
字符类:[ ] 表示有一系列字符可供选择,只要匹配其中一个就可以。所有可供选择的字符都放在方括号内。
// 只要包含有a 或者包含有b 或者c 都返回true
var rg = /[abc]/
console.log(rg.test('andy'))
// 三选一,只有是a 或是b 或是c 这三个字母才返回true
var rg2 = /^[abc]$/
console.log(rg2.test('aa')) // false
console.log(rg2.test('b')) // true
// 26个英文字母任何一个字母返回true
var rg3 = /^[a-z]$/
// 26个英文字母大写和小写任何一个字母返回true
var rg4 = /^[a-zA-Z]$/
var rg5 = /^[a-zA-Z0-9]$/
var rg6 = /^[a-zA-Z_-]$/
// 如果中括号里面有 ^ 表示取反的意思
var rg7 = /^[^a-zA-Z]$/
3.4量词符
量词符用来设定某个模式出现的次数。
var rg = /^a*$/
console.log(rg.test('')) // true
console.log(rg.test('a')) // true
console.log(rg.test('ab')) // false
console.log(rg.test('aaaa')) // true
用户名验证:/^[a-zA-Z0-9]{6,16}$/ {6,16}中间不要有空格
3.5括号总结
(1)大括号,量词符,里面表示重复次数。
(2)中括号,字符集合,匹配方括号中的任意字符。
(3)小括号,表示优先级。
// 这是让 abc 重复三次
var rg = /^(abc){3}$/
3.6预定义类
预定义类值得是某些常见模式的简写方式。
座机号码验证:两种格式: 010-12345678或者 0530-1234567
// 正则里面的或者符号 |
var rg1 = /^\d{3}-\d{8}|\d{4}-\d{7}$/
4.正则表达式中的替换
4.1 replace替换
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
var str = 'andy和red'
//var newStr = str.replace('andy','baby')
var newStr2 = str.replace(/andy/,'baby')