JS高级
1.类和对象
1.通过class关键字创建类,类名还是习惯性首字母大写
2.类里面有个constructor函数,可以接受传递过来的参数,同时返回实例对象
3.constructor函数只要new生成实例,就会自动调用这个函数,入锅不写这个函数,类也会自动生成这个函数
4.生成实例 new不能省略
5.最后注意语法规范,创建类,类名后面不要加小括号,生成实例 类名后面要加小括号,构造函数不需要加function
<script> class Star { constructor(uname, age) { this.uname = uname; this.age = age; } sing(song) { console.log(this.uname + song); } } var ldh = new Star('刘德华', 18); var zxy = new Star('张学友', 20); console.log(ldh); console.log(zxy); //我们类里面所有的函数不需要写function //多个函数方法之间不需要添加逗号分隔 ldh.sing('冰雨'); zxy.sing('李香兰'); </script>,
2.类的继承
extends关键字 继承父类的属性和方法
//类的继承 class Father { constructor() { } moner() { console.log(100); } } class Son extends Father { } var son = new Son(); son.moner();
super关键字用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数
class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class Son extends Father { constructor(x, y) { super(x, y); //调用了父类中的构造函数 } } var son = new Son(1, 2); son.sum();
class Father { say() { return '我是爸爸'; } } class Son extends Father { say() { // console.log('我是儿子'); console.log(super.say() + '的儿子'); //super.say()就是调用父类中的普通函数 say(); } } var son = new Son(); son.say(); //继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类 //继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有就去调用,(就近原则)
class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class Son extends 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(5, 3); son.subtract(); son.sum();
2.三个注意点
1.在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
2.类里面的共有的属性和方法一定要加this使用
3.类里面的指向问题
4.constructor 里面的this指向实例对象,方法里面的this指向这个方法的调用者
3.insertAdjacentHTML()
可以直接把字符串格式元素添加到父元素
-
'beforebegin'
:元素element自己的前面。 -
'afterbegin'
:插入到元素element里面的第一个子节点之前 -
'beforeend'
:插入元素element里面的最后一个子节点之后 -
'afterend'
:元素element自己的后面。
2.构造函数和原型
构造函数方法很好用,但是存在浪费内存的现象
function Star(uname, age) { this.uanme = uname; this.age = age; this.sing = function() { console.log('我会唱歌'); } } var ldh = new Star('刘德华', 18); //1.实例成员就是构造函数内部通过this添加的成员 uname age sing就是实例成员 //实例成员只能通过实例化的对象来访问 console.log(ldh.uname); //2.静态成员 在构造函数本身上添加的成员 sex就是静态成员 Star.sex = '男'; //静态成员只能通过构造函数来访问,不能通过对象来访问 console.log(Star.sex);
2.1构造函数原型prototype
构造函数通过原型分配的函数是所有对象所共享的
js规定,每个构造函数都有一个prototype属性,指向另一个对象,这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有的对象的实例就可以共享这些方法
原型是一个对象,我们称prototype为原型对象,原型的作用是共享方法
function Star(uname, age) { this.uanme = uname; this.age = age; // this.sing = function() { // console.log('我会唱歌'); // } } Star.prototype.sing = function() { console.log('我会唱歌'); } var ldh = new Star('刘德华', 18); ldh.sing(); //一半情况下,我们的公告属性定义到构造函数里面 //公共的方法放到原型对象身上
2.2对象原型proto
对象都会有一个属性protp指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有proto原型的存在
console.log(ldh); //对象身上系统自己添加一个——proto——指向我们构造函数的原型对象 // 方法的查找规则,首先看ldh对象身上是否有sing方法,如果有就调用 //如果没有,就去原型对象上查找
2.3constructor构造函数
指向的是构造函数本身
constructor主要用于记录该对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数
Star.prototype = { constructor: Star, sing: function() { console.log('我会唱歌'); }, movie: function() { console.log('我会演电影'); } } var ldh = new Star('刘德华', 18); ldh.sing(); console.log(ldh.__proto__); console.log(Star.prototype); //如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,我们需要手动的利用constructor这个属性指回原来的构造函数
2.4原型链
js的成员查找机制
1.当访问一个对象的属性(包括方法)时,首先会查找这个对象自身有没有该属性
2.如果没有就查找它的原型(也就是proto 指向的prototype原型对象)
3.如果还没有就查找原型对象的原型(object的原型对象)
4.依次类推一直找到object为止
5.proto 对象的原型的意义就在于为对象成员查找机制提供一个方法,或者说一条路线
2.5原型对象this的指向
在构造函数中,里面的this指向的是对象实例
原型对象函数里面的this指向的是实例化对象
2.6利用原型对象扩展内置对象
可以通过原型 对象,对原来的内置对象进行扩展自定义的方法,比如给数组添加自定义求偶数和的功能
//原型对象的应用 扩展内置对象方法 Array.prototype.sum = function() { var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i]; } return sum; } var arr = [1, 2, 3]; console.log(arr.sum()); console.log(Array.prototype); var arr1 = new Array(11, 22, 33); 注意:扩展内置对象的时候只能用.什么什么追加,不能用=function赋值
2.7call()
call() 调用这个函数,并且修改函数运行时的this指向
function fn(x, y) { console.log('我想喝咖啡'); console.log(this); console.log(x + y);//3 } var o = { name: 'adny' } fn.call(); //call()可以改变这个函数的指向 //此时这个函数的this指向,就指向了o fn.call(o, 1, 2);
2.8借用构造函数继承父类型属性
核心原理:通过call()把父类的this指向子类型的this,这样就可以实现子类型继承父类型的属性
//借用父构造函数继承属性 //1.父构造函数 function Father(uname, age) { //this 指向父构造函数的对象实例 this.uname = uname; this.age = age; } //2.子构造函数 function Son(uname, age, score) { //this 指向子构造函数的对象实例 Father.call(this, uname, age); this.score = score; } var son = new Son('刘德华', 18, 100); console.log(son);
2.9借用原型对象继承父类型方法
//借用父构造函数继承属性 //1.父构造函数 function Father(uname, age) { //this 指向父构造函数的对象实例 this.uname = uname; this.age = age; } Father.prototype.money = function() { console.log(1000000); } //2.子构造函数 function Son(uname, age, score) { //this 指向子构造函数的对象实例 Father.call(this, uname, age); this.score = score; } // Son.prototype = Father.prototype; 这样直接赋值有问题,如果修改了子原型对象则父原型对象也会改变 Son.prototype = new Father(); //重要两句 //如果利用对象的形式修改了原型对象,别忘了利用constrocutor指回原来的构造函数 Son.prototype.constructor = Son; //这个是子构造函数专有的方法 Son.prototype.exam = function() { console.log('孩子要考试'); } var son = new Son('刘德华', 18, 100); console.log(son); console.log(Father.prototype);
3.类的本质
class的本质还是函数
4.ES5新增方法
4.1数组方法
遍历方法:forEach()
array.forEach(function(currentValue,index,arr))
currentValue 数组当前项的值
index 数组当前项的索引
arr 数组对象本身
var arr = [1, 2, 3]; var sum = 0; arr.forEach(function(value, index, array) { sum += value; }) console.log(sum);
遍历方法filter()
filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于 筛选数组
注意它直接返回一个新数组
array.filter(function(currentValue,index,arr))
currentValue 数组当前项的值
index 数组当前项的索引
arr 数组对象本身
//filter 筛选数组 var arr = [12, 66, 4, 88]; var newArr = arr.filter(function(value, index) { return value >= 20; }) console.log(newArr);
遍历数组some()方法
array.some(function(currentValue,index,arr))
some()方法用于检测数组中的元素是否满足指定条件,通俗点查找数组中是否有满足条件的元素
注意它返回值是布尔值,如果查找到这个元素,就返回true,如果查找不到就返回false
如果找到第一个满足条件的元素则终止循环,不再查找
currentValue 数组当前项的值
index 数组当前项的索引
arr 数组对象本身
var arr = [10, 30, 4]; var flag = arr.some(function(value, index) { // return value >= 20; return value < 3; }) console.log(flag); var arr1 = ['red', 'pink', 'blue']; var flag1 = arr1.some(function(value, index) { return value == 'pink'; }) console.log(flag1); //1.filter 也是查找满足条件的元素,返回的是一个数组,而且是把所有满足的条件都返回 //2.some也是查找满足条件的元素是否存在,返回的是一个布尔值,如果查找到一个满足的元素就终止循环
4.2forEach和some区别
在forEach里面return不会终止迭代
在some里面遇到return true 就是终止遍历 迭代效率更高
如果想要找到唯一一个元素就用some();
4.3字符串方法
trim()方法会从一个字符串的两端删除空白字符
str.trim();
//trim方法去除字符串两侧空格,并且返回一个新字符串 var str = ' andy '; var str1 = str.trim(); console.log(str1);
<input type="text"><button>点击</button> <div></div> <script> //trim方法去除字符串两侧空格 var str = ' andy '; var str1 = str.trim(); console.log(str1); var input = document.querySelector('input'); var btn = document.querySelector('button'); var div = document.querySelector('div'); btn.onclick = function() { if (input.value.trim() == '') { alert('不能为空') } else { div.innerHTML = input.value.trim(); } }
4.4对象方法
Object.defineProperty(obj,prop,descriptor)//定义对象中新属性或修改原有的属性
obj:必需,目标对象
prop:必须,需定义或修改的属性的名字
descriptor:必需,目标属性所拥有的特性
第三个参数descriptor说明:以对象形式{}书写
value:设置属性的值,默认为undefined
writable:值是否可以重写,true和false 默认为fasle
enumerable:目标属性是否可以被枚举(是否可以被遍历),true和fasle默认为false
configurable:目标属性是否可以被删除或是否可以再次修改特性true和fasle,默认为false;
// Object.defineProperty()//定义对象中新属性或修改原有的属性 var obj = { id: 1, pname: '小米', price: 1999 } //1.以前的对象添加和修改属性的方式 // obj.num = 1000; // obj.price = 99; //2.新增方法 Object.defineProperty(obj, 'num', { value: 1000 }) console.log(obj); Object.defineProperty(obj, 'id', { //不允许修改这个值,默认值也是false writable: false, }) obj.id = 2; Object.defineProperty(obj, 'address', { value: "石家庄", //不允许修改这个值,默认值也是false writable: false, enumerable: false, configurable: false, }) console.log(Object.keys(obj)); delete obj.address; console.log(obj);
4.5 Object.keys()
用于获取对象自身所有的属性
Object.keys(obj)
效果类似于for in
返回一个由属性名组成的数组
var obj = { id: 1, pname: '小米', price: 1999, num: 2000 }; var arr = Object.keys(obj); console.log(arr); arr.forEach(function(value) { console.log(value); })
5.函数进阶
5.1函数的定义和调用
函数的定义方式
1.函数声明方式function 关键字(命名函数)
2.函数表达式匿名函数
3.new Function('参数1',‘参数2’,‘函数体’)
var f = new Function('a', 'b', 'console.log(a+b)'); f(1, 2); //所有函数都是Function的实例(对象)
5.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); //这个函数是定时器自己调用 //6.立即执行函数 (function() { console.log('人生的巅峰'); })(); //立即执行函数是自己调用;
5.3函数内this的指向
一般指向函数的调用者
普通函数:this指向window
对象的方法:this指向对象
构造函数:this指向实例对象
原型对象里面的this也指向实例对象
绑定事件函数:this指向的是函数的调用者
定时器函数:this指向的也是window
立即执行函数:this指向window
5.3三种改变函数this指向的方法
1.call()方法
可以调用函数,也可以改变函数的指向
call的主要作用可以实现继承
function fn(x, y) { console.log('我想喝咖啡'); console.log(this); console.log(x + y);//3 } var o = { name: 'adny' } fn.call(); //call()可以改变这个函数的指向 //此时这个函数的this指向,就指向了o fn.call(o, 1, 2);
2.apply方法
apply()方法调用一个函数,简单理解为调用函数的方式,但是它可以改变this的指向
this:在fun函数运行时指定的值
argsArray:传递的值,必需包含在数组里面
var o = { name: 'andy' } function fn(arr) { console.log(this); console.log(arr); //pink }; fn.apply(o, ['pink']); //1.也是调用函数,可以改变函数内部的this指向 //2.但是他的参数必需是数组(伪数组) //3.apply的主要应用 比如说我们可以利用apply借助数学内置对象来求最大值 var arr = [1, 66, 33, 99]; // var max = Math.max.apply(null, arr); var max = Math.max.apply(Math, arr); console.log(max);
3.bind方法 重点
bind()方法不会调用函数,但是能改变函数内部this指向
thisArg:在fun函数运行时指定的this值
arg1,arg2:传递的其他参数
返回由指定的this值和初始化参数改造的原函数拷贝
var o = { name: 'andy' } function fn(a, b) { console.log(this); console.log(a + b); } var f = fn.bind(o, 1, 2); f(); //1.不会调用原来的函数,可以改变原来函数内部的this指向 //2.返回的是原函数改变this之后产生的新函数
应用 //1.如果有的函数我们不需要立即调用,但是又想改变this指向 //需求:我们有一个按钮,当我们点击了之后,就禁用这个按钮,三秒之后就能用 // var btn = document.querySelector('button'); // btn.onclick = function() { // this.disabled = 'true'; //这个this指向调用者 // // var that = this; // setTimeout(function() { // // that.disabled = fales; //定时器函数指向window // this.disabled = fales; //此时this指向btn // }.bind(this), 3000) //这个this指向btn的this // } var btns = document.querySelectorAll('button'); for (var i = 0; i < btns.length; i++) { btns[i].addEventListener('click', function() { this.disabled = true; setTimeout(function() { this.disabled = false; }.bind(this), 2000) }) }
总结:
相同点:都可以改变函数内部的this指向
区别点:1.call和apply会调用函数,并且改变函数内部this指向
2.call和apply传递的参数不一样,call传递参数aru1,aru2形式,apply必须数组形式[arg];
3.bind不会调用函数,可以改变函数内部this指向
主要应用场景:
1.call经常做继承
2.apply经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
3.bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向
6.严格模式
即在严格的条件下运行js代码
严格模式对正常的javaScript语义做了一些更改:
1.消除了js语法的一些不合理 不严谨之处,减少了一些怪异行为
2.消除代码运行的一些不安全之处,保证代码运行的安全
严格模式可以应用到整个脚本或个别函数中,
1.为脚本开启
’use strict‘
6.1严格模式变化
1.变量规定
在正常模式中,如果一个变量没有声明就赋值,默认是全局变量,严格模式禁止这种语法,变量都必须先用var命名声明,再使用
严禁删除已声明变量
2.严格模式下this指向问题
1.以前在全局作用域函数中的this指向window对象
2.严格模式下全局作用域中函数中的this是undefined
3.以前构造函数时不加new也可以调用,当普通函数,this指向全局对象
4.严格模式下,如果构造函数不加new调用,this会报错
5.new实例化的构造函数指向创建的对象实例
6.定时器中的this还是指向window
7.事件 对象还是指向调用者
3.函数变化
1.函数里面的参数不允许有重名
2.函数必须声明在在顶层,不允许在非函数的代码块内声明函数
7.高阶函数
高阶函数是对其他函数进行操作的函数,它接受函数作为参数或将函数作为返回值输出
7.1闭包
闭包指有权访问另一个函数作用域中变量的函数
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量
//闭包 我们fun这个函数作用域访问了另外一个函数fn里面的局部变量num function fn() { var num = 10; function fun() { console.log(num); } fun(); } fn();
7.2闭包的作用
//闭包 我们fun这个函数作用域访问了另外一个函数fn里面的局部变量num //我们fn外面的作用域也可以访问fn局部变量 //闭包的主要作用:延申了变量的作用范围 function fn() { var num = 10; // function fun() { // console.log(num); // } // return fun; return function() { console.log(num); } } var f = fn(); f(); //类似于 // function fun() { // console.log(num); // }
//2.利用闭包的方式得到当前小li的索引号 for (var i = 0; i < lis.length; i++) { //利用for循环创建了4个立即执行函数 //立即执行函数也称为小闭包因为立即执行函数里面的任何一个函数都可以使用它的i变量 (function(i) { // console.log(i); lis[i].onclick = function() { console.log(i); } })(i); }
7.3闭包的理解和this指向问题
1. this指向: 普通函数: - 函数直接调用(fn()), this指向window - 函数通过对象去调用(obj.fn()), this指向调用的对象 - new调用函数,this指向生成实例对象 - 函数通过call/apply方法调用,this指向call/apply方法传入的第一个参数 特殊函数: 箭头函数:和调用无关,this指向外部函数this 回调函数: DOM事件回调函数:this指向绑定事件的DOM元素 定时器回调函数:this指向window 2. 闭包 - 概念 通过Chrome开发者调试工具查看可知,闭包是一个特殊容器(Closure 特殊对象)。 特殊容器保存在内部函数中 特殊容器保存内部函数引用外部函数的局部变量 - 产生条件 函数嵌套 内部函数引用外部函数的局部变量 调用外部函数 当内部函数定义执行完时,才产生闭包 - 优点/缺点 优点: 延长局部变量生命周期(让局部变量活的久点) 让函数外部可以操作函数内部的局部变量数据 缺点: 可能会导致内存泄漏(解决:及时释放,让内部函数成为垃圾对象) - 生命周期(产生和死亡) 产生:当内部函数定义执行完时,才产生闭包 死亡: 当内部函数成为垃圾对象(内部函数死,闭包跟着一起死) */
8.递归函数
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
简单理解:函数内部自己调用自己,这个函数就是递归函数
function fn(n) { if (n == 1) { return 1; } return n * fn(n - 1); } console.log(fn(3)); //递归阶乘
<script> var data = [{ id: 1, name: '家电', goods: [{ id: 11, ganme: '冰箱', goods: [{ id: 111, gname: '海尔' } ] }, { id: 12, ganme: '洗衣机' }] }, { id: 2, name: '服饰' } ] //我们想要做输入id号,就可以返回的数据对象 function getID(json, id) { var o = {}; json.forEach(function(value) { // console.log(value); if (value.id == id) { o = value; //我们想要得到里层的数据,利用递归 //里面应该有godds这个数组并且数组长度不为0 } else if (value.goods && value.goods.length > 0) { o = getID(value.goods, id); } }) return o; } console.log(getID(data, 1)); console.log(getID(data, 2)); console.log(getID(data, 11)); console.log(getID(data, 12)); console.log(getID(data, 111));
9.浅拷贝和深拷贝
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
深拷贝拷贝多层,每一级别的数据都会拷贝
浅拷贝只是拷贝了一个地址
Object.assign(target,...sources) es6 新增方法
第一个参数 拷贝给谁
第二个参数 拷贝谁
//浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用 //深拷贝拷贝多层,每一级别的数据都会拷贝 var obj = { id: 1, name: 'andy', msg: { age: 18, } }; var o = {}; // for (var k in obj) { // // k是属性名 obj[k] 属性值 // o[k] = obj[k]; // } // console.log(o); // o.msg.age=20; // console.log(obj); console.log('-------------'); Object.assign(o, obj); console.log(o); o.msg.age = 20; console.log(obj);
深拷贝 var obj = { id: 1, name: 'andy', msg: { age: 18, }, color: ['pink', 'red'] }; var o = {}; //封装函数 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], item); } else { //4.属于简单类型 newobj[k] = item; } } } deepCopy(o, obj); console.log(o);
手写深拷贝(简单)
function deepCopy(oldobj) { if(typeof oldobj!=='object'||oldobj===null){ return oldobj; }; var newobj=oldobj instanceof Array?[]:{}; for (const key in oldobj) { if (Object.hasOwnProperty.call(oldobj, key)) { var item = oldobj[key] newobj[key]=deepCopy(item) } } return newobj; };
10.正则表达式
正则表达式是用于匹配字符串中字符组合的模式,在js中,正则表达式也是对象
1.验证表单2.替换敏感词3.提取特定部分
特点:灵活性逻辑性和功能性非常强,可以迅速的用极简单的方式达到字符串的复杂控制,实际开发一般都是直接复制写好的表达式,但要求会修改
10.1创建正则表达式
//1.利用RegExp对象来创建正则表达式 var regexp = new RegExp(/123/); console.log(regexp); //2.通过字面量创建 var rg = /123/; //3.test方法用来检测字符串是否符合正则表达式要求的规范 console.log(rg.test(123));
10.2边界符
^ 以什么开头
$以什么结尾
var rg = /abc/; //正则表达式里面不需要加引号 不管是数字还是字符串 // /abc/ 只要包含有abc这个字符串返回的都是true console.log(rg.test('abc')); console.log(rg.test('aabc')); console.log(rg.test('abcc')); var reg = /^abc/; console.log(reg.test('abc')); console.log(reg.test('aabc')); console.log(reg.test('abcc')); var reg1 = /^abc$/; //精确匹配要求必须是abc字符串才符合规范 console.log(reg1.test('abc')); console.log(reg1.test('aabc')); console.log(reg1.test('abcc'));
10.3字符类
//字符类:[] 表示有一系列字符可供选择,只要匹配其中一个就可以了 var rg = /[abc]/; console.log(rg.test('andy')); //true var reg1 = /^[abc]$/; //三选一 只有是a或者是b 或者是c这三个字符才返回true console.log(reg1.test('andy')); console.log('------------'); var rg1 = /^[a-z]$/; //26个英文字母任何一个字母返回true console.log(rg1.test('a'));
//字符组合 var rg1 = /^[a-zA-Z0-9—_-]$/; //26个英文字母大写小写任何一个字母返回true console.log(rg1.test('a')); console.log(rg1.test('B')); console.log(rg1.test('8')); console.log(rg1.test('-')); //如果中括号里面有^表示取反的意思,不能有这些 var rg2 = /^[^a-zA-Z0-9—_-]$/; console.log(rg2.test('a')); console.log(rg2.test('B')); console.log(rg2.test('8')); console.log(rg2.test('-'));
10.4量词符
//量词符:用来设定某个模式出现的次数 //简单理解:就是让下面的a这个字符重复多少次 // var reg = /^a$/; //*相当于>=0 可以出现0此或者多次 // var reg = /^a*$/; // console.log(reg.test('')); // console.log(reg.test('aaaa')); // + 相当于>=1 可以出现1此或者很多次 // var reg = /^a+$/; // console.log(reg.test('')); // console.log(reg.test('aaaa')); // ?相当于1||0 // var reg = /^a?$/; // console.log(reg.test('')); // console.log(reg.test('a')); // console.log(reg.test('aaaa')); // {3}就是重复3次 // var reg = /^a{3}$/; // console.log(reg.test('')); // console.log(reg.test('a')); // console.log(reg.test('aaaa')); //{3,} 大于等于3 // var reg = /^a{3,}$/; // console.log(reg.test('')); // console.log(reg.test('a')); // console.log(reg.test('aaaa')); //{3,16} 大于等于3 并且小于等于16 var reg = /^a{3,16}$/; console.log(reg.test('')); console.log(reg.test('a')); console.log(reg.test('aaaa'));
// 量词是设定某个模式出现的次数 var reg = /^[a-zA-Z0-9_-]{6,16}$/; //中间不能有空格 //这个模式用户只能输入英文字母 数字下划线 短横线,但是有边界符和[]这就限定了只能多选1 console.log(reg.test('adny-red')); console.log(reg.test('adny0007')); console.log(reg.test('adny0!007'));
//中括号 字符集合 匹配方括号中的任意字符 var reg = /^[abc]$/; //a 也可以 b 也可以 c也可以 //大括号 量词符 里面表示重复次数 var reg = /^abc{3}$/; //它只是让c重复三次 console.log(reg.test('abccc')); console.log(reg.test('abcabcabc')); //小括号 表示优先级 var reg = /^(abc){3}$/; console.log(reg.test('abccc')); console.log(reg.test('abcabcabc'));
10.5预定义类
\d 匹配0-9之间的任一数字 相当于[0-9]
\D 匹配所有0-9以外的字符,相当于[^0-9}
\w 匹配任意的字母数字和下划线 相当于[A-Za-z0-9]
\W除所有字母 数字 下划线意外的字符相当于[^A-Za-z0-9】
\s 匹配空格(包括换行符 制表符 空格符等)相当于[\t\r\n\v\f]
\S匹配非空格的字符相当于[^\t\r\n\v\f】
\b:把\b包裹的当作单词匹配
//正则里面的或者符号 | var reg = /^\d{3}-\d{8}|\d{4}-\d{8}$/;
10.6正则表达式中的替换
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式
第一个参数:被替换的字符串或者正则表达式
第二个参数 替换为的字符串
返回值是一个替换完毕的新字符串
正则表达式参数
switch(也称为修饰符)按照什么样的模式来匹配,有三种植
g:全局匹配
i:忽略大小写
gi:全局匹配加忽略大小写
m:换行也能匹配
// 替换 replace // var str = 'andy和red'; // var newstr = str.replace('andy', 'baby'); // console.log(newstr); var text = document.querySelector('textarea'); var btn = document.querySelector('button'); var div = document.querySelector('div'); btn.onclick = function() { div.innerHTML = text.value.replace(/激情|gay/g, '**'); }
10.7 验证表单
function regexp(ele, reg) { ele.addEventListener('blur', function() { if (reg.test(this.value)) { // console.log(('正确的')); this.nextElementSibling.className = 'success'; this.nextElementSibling.innerHTML = '<i class="success_icon"></i>恭喜您输入正确'; } else { // console.log('错误的'); this.nextElementSibling.className = 'error'; this.nextElementSibling.innerHTML = '<i class="error_icon"></i>格式不正确,请从新输入'; } }) };
10.8正则方法
test:
split:
match:
search:
replace:
-
split
var str = "1a2b3c4d5e6f7"; /* * split() * - 可以将一个字符串拆分为一个数组 * - 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串 * - 这个方法即使不指定全局匹配,也会全都拆分 */ /* * 根据任意字母来将字符串拆分 */ var result = str.split(/[A-z]/); console.log(result);
-
search
/* * search() * - 可以搜索字符串中是否含有指定内容 * - 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1 * - 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串 * - serach()只会查找第一个,即使设置全局匹配也没用 */ str = "hello abc hello aec afc"; /* * 搜索字符串中是否含有abc 或 aec 或 afc */ result = str.search(/a[bef]c/); //console.log(result);
-
match[匹配]
/* * match() * - 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来 * - 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索 * 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容 * 可以为一个正则表达式设置多个匹配模式,且顺序无所谓 * - match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果 * 如果没有符合规则的,返回null * */ str = "1a2a3a4a5e6f7A8B9C"; result = str.match(/[a-z]/ig); console.log(result[2]);
-
replace[替换]
增删改 test match 查 /* * replace() * - 可以将字符串中指定内容替换为新的内容 * - 参数: * 1.被替换的内容,可以接受一个正则表达式作为参数 * 2.新的内容 * - 默认只会替换第一个 */ str = "1a2a3a4a5e6f7A8B9C"; //result = str.replace(/[a-z]/gi , "@_@"); result = str.replace(/[a-z]/gi , ""); console.log(result); // 增 /** * item: 标识正则匹配到的当前字符 * index: 标识正则匹配到的当前字符对应的索引 * */ result = str.replace(/[a-z]/ig, function(item,index){ // 返回值就是替换的新内容 // 原值 + 新增加的值 return item + '@'; }) console.log(result);
11.ES6的新增语法
11.1let关键字
let es6中新增的用于声明变量的关键字
let声明的变量只在所处于的块级有效,大括号内有效
在一个大括号中使用let关键字声明的变量才具有块级作用域
var关键字是不具备这个特点的
防止循环变量变成全局变量
let不存在变量提升
使用let关键字声明的变量具有暂时性死区特性
在块级作用域中let被绑定到块级作用域内
经典面试题一 var arr = []; for (var i = 0; i < 2; i++) { arr[i] = function() { console.log(i); } } arr[0]();//2 arr[1]();//2 输出的i全都是全局作用域下的
let arr = []; for (let i = 0; i < 2; i++) { arr[i] = function() { console.log(i); } } arr[0]();//0 arr[1]();//1 此题的关键点在于每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的,函数执行时疏忽的是自己上一级(循环产生的块级作用域)作用域下的i值;
11.2const关键字
作用:声明常量,常量就是值(内存地址)不能变化的量
同样具有块级作用域
声明常量时必须赋值;常量赋值后,值不能修改
11.3总结
let const var 的区别
使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
使用const声明的时常量,在后面出现的代码中不能再修改该常量的值
11.4数组解构
ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构
//数组解构允许我们按照一一对应的关系从数组中提取值然后将值赋值给变量 let ary = [1, 2, 3]; let [a, b, c, d, e] = ary; console.log(a); console.log(b); console.log(c); console.log(d); console.log(e); //如果解构不成功就会显示undeifined;
11.5对象解构
//对象解构允许我们使用变量的名字匹配对象的属性,匹配成功将对象属性的值赋值给变量 let person = { name: 'list', age: 30, sex: '男' }; let { name, age, sex } = person; console.log(name); console.log(age); console.log(sex); //另一种写法 let { name: myName } = person; console.log(myName);//list
11.6箭头函数
ES6中新增的定义函数的方式
()=>{};
const fn=()=>{};
//箭头函数是用来简化函数定义语法的 const fn = () => { console.log(123); } fn(); //函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号 // function sum(num1, num2) { // return num1 + num2; // } const sum = (num1, num2) => num1 + num2; const result = sum(10, 20); console.log(result); //如果形参只有一个,形参外侧的小括号也可以省略; // function fn(v) { // return v; // } const su = v => { alert(v); } su(20);
箭头函数不绑定this关键字
//箭头函数不绑定this,箭头函数没有自己的this关键字 如果在箭头函数中使用this //this关键字将指向箭头函数定义位置中的this function fn() { console.log(this); return () => { console.log(this); //obj对象 } } const obj = { name: 'zhangsan' }; const resFn = fn.call(obj); resFn(); //obj对象
var obj = { age: 20, say: () => { alert(this.age); } } obj.say();//undefined,对象是不能产生作用域的,所以this指向window
11.7剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组
const sum = (...args) => { let total = 0; args.forEach(item => total += item); return total; }; console.log(sum(10, 20)); console.log(sum(10, 20, 30));
//剩余参数和数组解构的应用 let ary1 = ['张三', '李四', '王五']; let [s1, ...s2] = ary1; console.log(s1); console.log(s2);
11.8扩展运算符
//扩展运算符可以将数组拆分成以逗号分隔的参数序列 let ary = ['a', 'b', 'c']; //...ary//'a' 'b' 'c'; console.log(...ary);//a b c
//扩展运算符应用于数组合并 // 方法1: let ary1 = [1, 2, 3]; let ary2 = [4, 5, 6]; // ...ary1//1,2,3 // ...ary2//4,5,6; let ary3 = [...ary1, ...ary2]; console.log(ary3); //方法2 ary1.push(...ary2); console.log(ary1);
//利用扩展运算符将伪数组转换为真数组 var oDivs = document.getElementsByTagName('div'); console.log(oDivs); var ary = [...oDivs]; console.log(ary); //伪数组转换为数组之后就可以调用数组方法 ary.push('a'); console.log(ary);
11.9Array.from()
构造函数方法:Array.from();
<script> var arrayLike = { "0": '张三', "1": '李四', "2": '王五', "length": 3 } var ary = Array.from(arrayLike); console.log(ary); </script>
<script> var arrayLike = { "0": '1', "1": '2', "length": 2 } var ary = Array.from(arrayLike, item => item * 2); console.log(ary); </script>
11.10 array.find()
用于找出第一个符合条件的数组成员,如果没有找到则返回undefined;
<script> var ary = [{ id: '1', name: '张三' }, { id: 2, name: '李四' }]; var target = ary.find(item => item.id == 2 ) console.log(target); </script>
11.11findlndex()
用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1
let ary = [10, 20, 50]; let index = ary.findIndex(item => item > 15 ) console.log(index);
11.12includes();
表示某个数组是否包含给定的值。返回布尔值
<script> let ary = ["a", "b", "c"]; var a = ary.includes('a'); console.log(a); </script>
12 模板字符串
s6新增创建字符串的方法
<script> let name = `张三`; let sayhellow = `hellow,我的名字叫${name}`; console.log(sayhellow); </script>
模板字符串可以换行显示
let result = { name: 'zhangsan', age: 20 }; let html = ` <div> <span>${result.name}</span> <span>${result.age}</span> </div> `
模板字符串也可以调用函数
const fn = () => { return '我是fn函数'; } let html = `我是模板字符串${fn()}`; console.log(html);
12.1starsWidth()和endsWidth()
starsWidth():表示参数字符串是否再原字符串的头部,返回布尔值
endsWidth():表示参数字符串是否再原字符串的尾部,返回布尔值
let str = 'Hello fantenglong!'; let r1 = str.startsWith('Hello'); console.log(r1); let r2 = str.endsWith('!'); console.log(r2);
12.2repeat()
repeat()方法表示将原字符串重复n次,并返回一个新字符串
<script> console.log('y'.repeat(5)); </script>
13.Set数据结构
类似于数组,但是成员的值都是唯一的,没有重复的值
<script> const s1 = new Set(); console.log(s1.size); const s2 = new Set(['a', 'b']); console.log(s2.size); //set 数组去重 const s3 = new Set(['a', 'a', 'b', 'b']); console.log(s3.size); const ary = [...s3]; console.log(ary); </script>
set:无序不重复的值 var set=new Set([3,1,1,1,1])//去掉重复值 set.delete(1);删除 set.add(2);添加 console.log(set.has(3));是否包含某个元素
13.1set遍历
const s5 = new Set(['a', 'b', 'c', 'e', 'f']); s5.forEach(value => { console.log(value);
14.判断数据类型的三种方法
//1.typeof 只能区分基本数据类型,引用数据类型则全部返回Object var arr=[1,2,3]; console.log(typeof arr); //2.instanceof //判断一个对象是不是一个类(构造函数)的实例对象 //instanceof是按照原型链来判断是否属于的 console.log(arr instanceof Array);//true console.log(obj instanceof Array);//false console.log(arr instanceof Object);//true //3.Obejct.prototype.toString.call(); console.log(Object.prototype.toString.call(arr));//Array var result=Object.prototype.toString.call(arr); var p1=result.slice(8,-1); console.log(p1);
15.防抖
多次触发但是只执行一次
function dbounce(fn,delay){ let timer=null; return function(){ clearTimeout(timer); timer=setTimeout(()=>{ fn.apply(this,arguments) },delay) } }
应用:
var ipt=document.querySelector('input'); ipt.addEventListener('keyup',debounce(()=>{ console.log(ipt.value); },2000)); function debounce(fn,delay){ let timer=null; return function(){ clearTimeout(timer); timer=setTimeout(()=>{ fn.apply(this,arguments); },delay) } } //防抖: 闭包 定时器 箭头函数 this arguments
16.节流
一段时间内只能执行一次
function throttle(fn,delay){ let flag=true; return function(){ if(flag){ setTimeout(()=>{ fn.apply(this,arguments); flag=true; },delay) flag=false; } } }
应用:
btn.addEventListener('click',throttle(()=>{ console.log(1); },1000)) function throttle(fn,delay){ let flag=true; return function(){ if(flag){ setTimeout(()=>{ fn.apply(this,arguments); flag=true; },delay) flag=false; } } }