一、正则表达式
1.1 元字符
- \d 一位数字 (0-9)
- \D一位非数字
- \s 1位空白 (空格 缩进 换行)
- \S 1位 非空白
- \w 一位字母 数字 下划线
- \W 一位非字幕数字下划线
- .(点)任意内容 (换行不算)
- .\ 转义字符
1.2 边界符
- ^ 开头符号
- $ 结尾符号
var set = /^abc$///表示前后必须为abc
var ret = /^a/dc$///表示前面必须是a 中间必须包含一位数字,最后必须是c
console.log(set.test("sada"))
1.3 限定符
- * 0~多次
- + 1~多次
- {n} 指定n个
- {n,} >=n个
var ret = /abc{2} //表示出现a,b,c,c这几个元素
1.4 特殊符号
- ()标是一个整体的意思
var ret = /^(abc){2}$/ //表示a b c都要出现两次
- | 或的意思:表示的是左右两边随便的一边的整体
- [] :表示包含[]里面任意一位一样的元素就算对
- [^]:表示包含[]里面不包含任意一位一样的元素就算对
2. 捕获exec
补捉先满足条件的内容,返回值为数组
var a =/asdas/g //会让test勤劳起来,不会再次从首字母开始查询满足的条件
var b = /asdas/i //表示其在查询 的时候不会分大小写进行查询
var time = "time is 2022.1.3 12:20:op"
var newtime = /\d{2}:\d{2}/
console.log(newtime.exec(time))
2.1正则表达式的特性
1.懒惰, 解决 使用全局标识符g
2.贪婪 : 它会将占用所有可以用到的条件,比如说:叫你拿3~5个,他必须要拿5个
3.非贪婪 加问号var reg= /\d{1,4}?/
2.2 正则与字符串的方法
解释:
1.replace 因为replace在进行替换的时候只能选中靠前面的所要替换掉的内容,现在我们可以通过正则表达式,来选取全部的所要的元素
var str = 'dasdwaxd'
var newstr = str.replace(/a/g,"k")//这就是可以加个g就表示是全局的变量,就可以替换所有的"a"元素了
search 他不能用上述方法
match捕获内容
var datestr
"time is from 2029-01-01 12:20:20 to 229-11-01
12:20:20"
console.log(datestr.match(/(\d[4})-(\d[1,2))-(\d[1,2))/g))
3. this指向
3.1 初识this
- this是一个对象
- 谁调用this,this就是谁
- 函数调用的事件this
① 全局作用下,this指向的是window;
② 函数独立调用时,函数内部的this也指向window
③ 被嵌套的函数独立调用时,this默认指向了window
全局:
function test(){
console.log(this);
}
console.log(this);
对象:
box.onclick = function(){
console.log(this);
}
3.2 改用this
- call
- apply
- bind
3.2.1 call
call 执行函数,并改变this执行为函数的第一个参数支持多个参数
call() 方法的第一个参数必须是指定的对象,然后方法的原参数,挨个放在后面。
(1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么;
(2)第二个参数开始:将原函数的参数往后顺延一位
function fun() {
console.log(this); // 原来的函数this指向的是 Window
}
fun();
function fun(a, b) {
console.log(this); // this指向了输入的 字符串call
console.log(a + b);
}
//使用call() 方法改变this指向,此时第一个参数是 字符串call,那么就会指向字符串call
fun.call('call', 2, 3) // 后面的参数就是原来函数自带的实参
3.1.2 apply
apply 执行函数, 并改变this执行为函数的第一个参数两个参数, 第二个参数是一个数组
apply() 方法的第一个参数是指定的对象,方法的原参数,统一放在第二个数组参数中。
(1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么;
(2)第二个参数开始:将原函数的参数放在一个数组中
function fun() {
console.log(this); // 原来的函数this指向的是 Window
}
fun();
function fun(a, b) {
console.log(this); // this指向了输入的 字符串apply
console.log(a + b);
}
//使用apply() 方法改变this指向,此时第一个参数是 字符串apply,那么就会指向字符串apply
fun.apply('apply', [2, 3]) // 原函数的参数要以数组的形式呈现
3.1.3 bind
bind() 方法的用法和call()一样,直接运行方法,需要注意的是:bind返回新的方法,需要重新调用
bind 改变this指向为函数的第一个参数,不会自动执行函数/支持多个参数
function fun() {
console.log(this); // 原来的函数this指向的是 Window
}
fun();
function fun(a, b) {
console.log(this); // this指向了输入的 字符串bind
console.log(a + b);
}
//使用bind() 方法改变this指向,此时第一个参数是 字符串bind,那么就会指向字符串bind
let c = fun.bind('bind', 2, 3);
c(); // 返回新的方法,需要重新调用
// 也可以使用下面两种方法进行调用
// fun.bind('bind', 2, 3)();
// fun.bind('bind')(2, 3);
四、ES6
4.1 ES6定义变量
增加了let与 const
let与var区别
- 必须先定义才能够使用
- 变量重名会报错
- 块级作用域,在块级里面定义的变量在外部不可利用,有助于防止变量冲突
let与const的去别
let是一个定义变量的,而const是定义常量的
const定义的时候必须赋值,因为const定义过后的常量不能够改变
let 的 暂存性死亡:
- 只要我在本代码块内声明了 i,那就只能使用本代码块内声明的 i,哪怕在我定义之前使用了i也不能使用外边的i(霸道)
- let、const不存在变量提升(这也就导致程序会报错,而不输出undefined)
示范:
let i = 0
{//这就是一个块的起始
console,log(i)
let i = 1
}//块的结束
这样会使浏览器报错
4.2 箭头函数
对于之前函数的差别
如果形参只有一个,则小括号可以省略;
函数体如果只有一条语句,则花括号可以省略,并省略return,函数的返回值为该条语句的执行结果;
箭头函数 this 指向声明时所在作用域下 this 的值;
箭头函数不能作为构造函数实例化;
不能使用 arguments;(一个特殊的数组,arguements[0]=1,可以取0,1,2)
const multiply = num => num * num;
==>const multiply = function (num) { return num * num; };
他们之间是相等价的
如果返回的结果是对象,则需要配上 ()
const func = val => ({ value: val });
不适合的场景
1、对象的方法:
const obj = {
x: 1,
print: () => {
console.log(this === window); // => true
console.log(this.x); // undefined
}
};
obj.print();
print 方法用了箭头函数,其内部的 this 指向的还是上下文 window,上下文中并没有定义 x,所以 this.x 输出为 undefined。
但是我们可以利用这个规则,制作返回上个函数内部进行的函数的再次调用
4.3 结构赋值
语法:
数组: let [a] =[1] [变量名]:变量名可随意
对象: let {name} = {name} {变量名}:变量名必须是对象中的属性名
- 数组:
按顺序: let [a,b,c] = [1,2,3]; console.log(a,b,c); //1,2,3
打乱顺序: let [b,a,c] = [1,2,3]; console.log(a,b,c); //2,1,3
数组的是按照位置来进行结构的,所以与变量名字无关
let [a, [b,c], d] = [1, [2, 3], 4];
console.log(a,b,c,d)
//1,2,3,4
//结构和位置一一对应就行了.
- 对象:
按顺序: let {name,sex} = {name:"fanfusuzi",sex:"man"}; console.log(name,sex); //fanfusuzi,man
打乱顺序: let {sex,name} = {name:"fanfusuzi",sex:"man"}; console.log(sex,name); //man,fanfusuzi
对象是按照属性名字进行结构的,所以与变量的位置无关
不存在的属性名: let {name,age} = {name:"fanfusuzi",sex:"man"}; console.log(name,age); //fanfusuzi,undefined
- 重命名(先取再重命名)
数组:我们上面说过,数组解构的时候只要注意位置对应就行了,名称啥的无所谓,你喜欢叫什么变量名就什么变量名
对象:对象解构的时候是要属性名对应才能取到值.但是没有说取到值之后不能重命名啊.一定要取到值之后在命名
let {name:myName,age} ={name:'ning',age:18}
//这里name:myName的意思是:取到name属性值,冒号后面的变量名没有花括号,意思是把我取到的值交给冒号后面的变量名,即'myName'.相当于把name变量重命名为myName
/**而student:{name},同样是'属性名:'意思一样,取里面对应的属性,冒号后面还有花括号,所以再解构,取student里面的name属性/
console.log(name,myName,age)
//undefined,ning,18
4.4 展开运算符
- 对于数组:
var arr = [1,2,3]
// 复制一个数组
let arr2=[...arr]
arr2.push(4);
// 并且不会对arr造成影响
console.log("arr",arr);
console.log("arr2",arr2);
// 连接数组
let arr3=[...arr,...arr2]
console.log(arr3);
- 对于对象的使用
var obj1 = { foo: 'yuan', x: 42 };
var obj2 = { foo: 'li', y: 13 };
// 克隆对象一定要加上{}
var clonedObj = { ...obj1 };
console.log("克隆后的对象",clonedObj);
// 同样的修改复制后的并不会影响原来的对象
clonedObj.foo="ss"
console.log("clonedObj",clonedObj);
console.log("obj1",clonedObj);
// 合并后的对象:
var mergedObj = { ...obj1, ...obj2}
console.log("合并后的对象",mergedObj);
// 当然也可以在合并时添加新的属性
var mergedObj = { ...obj1, ...obj2,address:"上海"}
console.log("合并后的对象",mergedObj)
4.5 ES6模块化语法
模块化解决问题: 1.私密不漏2.重名不怕3.依赖不乱
- 只导出一次(exrepot defause )
注意:只能导出一次,多了就会报错
- import 任意名称 from ‘模块标识符’
// import-default.js
import customName from './export-default';
customName(); // 'foo'
- .按需导入导出: export 按需导出的成员
/** 定义模块 math.js **/
var basicNum = 0;
var add = function (a, b) {
return a + b;
};
export { basicNum, add };
- 按需导入: import { s1 } from ‘模块标识符’
可以通过as 关键字来更改变量名。
/** 引用模块**/
import { basicNum, add } from './math';
function test(ele) {
ele.textContent = add(99 + basicNum);
}
5.1 初识面向对象
- 首先,我们要明确,面向对象不是语法,是一个思想,是一种 编程模式面向: 面 (脸) ,向 (朝着)
- 面向过程: 脸朝着过程 =》关注着过程的编程模式面向对象:
- 脸朝着对象=》关注着对象的编程模式实现一个效果
- 在面向过程的时候,我们要关注每一个元素,每一个元素之间的关系,顺序,。在面向过程的时候,我们要关注的就是找到一个对象来帮我做这个事情,我等待结果
- 我们以前的编程思想是,每一个功能,都按照需求一步一步的逐步完成
5.2 创建对象函数的方式
- 工厂函数:
function createObject(name){
var obj = {}
obj.name = name
onj.matical = []
return obj
}
var obj1 = createObject('shaokao')
- 自定义函数
function createObject(name){
this.name = name
this.martical = []
this.coke = function(){
}
}
var obj2=new createObject("第三次")
5.3 面向对象原型
概念:
在典型的 OOP 的语言中(如 Java),都存在类的概念,类就是对象的模板,对象就是类的实例,但在 ES6之前, JS 中并没用引入类的概念。
ES6, 全称 ECMAScript 6.0 ,2015.06 发版。但是目前浏览器的 JavaScript 是 ES5
版本,大多数高版本的浏览器也支持 ES6,不过只实现了 ES6 的部分特性和功能。在 ES6之前 ,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和它们的特征。
2.对象原型 __ proto _
- 对象都会有一个属性__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在。
- _proto_对象原型和原型对象prototype是等价的。
- _proto_对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype
5.4 class类
cLass createobj {
//构造器函数
constructor( name){
this.name =name
}
}
5.5 继承
构造函数继承
function student(name ,age,classroom){
Person.ca11(this,name , age)
this.classroom = classroom
}
原型继承
student.prototype = new Person0
组合继承
构造函数继承+原型继承
function Person(name , age){
this.name = name
this.age = age
}
5.6 ES6继承
//夫类
class Person{
constructor(name,age){
this.name = name
this.age = age
}
say(){
console.log("hello")
}
}
//extends继承
class Student extends Person{
constructor(name,age,grad){
super(name,age) //super相当于Person.call(this,name,age).而且super必须写到constructor里面的第一行
this.grad = grad
}
//直接可以改变Parson里面的方法使自己使用
say(){
super.say()//调用父元素的say()使其不会被覆盖
document.write("bjsad")//修改say()方法,将其覆盖,若加上super就不会被覆盖
}
}
var obj = new Student("asd",100,100)
console.log(obj.grad)
obj.say()
6.初识前后端交互
6.1 ajax
AJAX 的优势
1.不需要插件的支持,原生js 就可以使用
2.用户体验好(不需要刷新页面就可以更新数据)
3.减轻服务端和带宽的负担
4.缺点: 搜索引擎的支持度不够,因为数据都不在页面上,搜索引擎搜索不到
AJAX 的使用
- 在js 中有内置的构造函数来创建 aiax 对象
- 创建 ajax 对象以后,我们就使用 ajax 对象的方法去发送请求和接受响应
创建步骤:
- 创建XHR ==》new XMLHTTPRequest()
- 配置open(请求方式,请求地址,是否同步)
- send发出
- 接受数据,创造一个事件
ajax状态码 200ok 404error
- ajax 状态码-xhr.readystate
- 是用来表示一个 ajax 请求的全部过程中的某一个状态
- readystate === 0 :表示未初始化完成,也就是open方法还没有执行
- readyState === 1:表示配置信息已经完成,也就是执行完open 之后
- readystate === 2 : 表示send 方法已经执行完成
- readystate === 3 :表示正在解析响应内容o
- readystate === 4 :表示响应内容已经解析完毕,可以在客户端使用了
- 这个时候我们就会发现,当一个 ax请求的全部过程中,只有当 r
- eadystate === 4 的时候,我们才可以正常使用服务端给我们的数据 所以,配合 http 状态码为 200 ~ 299
- 一个ajax 对象中有一个成员叫做 xhr.status这个成员就是记录本次请求的 http
- 状态码的两个条件都满足的时候,才是本次请求正常完成
var xhr = new XMLHttpRequest()
// ip:js%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0
xhr.open("GET","http://127.0.0.1:5500/js%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0/01.text")
xhr.send()
//当后端与前端接上头后执行该函数
xhr.onreadystatechange = function(){
// console.log("edkw");
if(xhr.readyState===4 &&xhr.status === 200){
console.log("此时已经加载完毕");
}else if(xhr.readyState === 4 && xhr.status===404){
console.log("没有找到这个对象");
}
}
//两种区别为:onload判断一次,而onreadstatechange判断四次
// xhr.onload = function(){
// // console.log(xhr.responseText)
// if(xhr.status==200){
// document.write(xhr.responseText)
// }else if(xhr.status===404){
// console.error("没有找到这个页面")
// // location.href ="404.html
// }
// }
案例:ajax
script部分
<ul id="malist"></ul>
<button id="btn">lisy</button>
<script>
btn.onclick = function(){
var xhr = new XMLHttpRequest()
// ip:js%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0
xhr.open("GET","http://127.0.0.1:5500/js%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0/data.json")
xhr.send()
//当后端与前端接上头后执行该函数
xhr.onreadystatechange = function(){
// console.log("edkw");
if(xhr.readyState===4 && xhr.status === 200){
console.log("此时已经加载完毕");
var jsondata = JSON.parse(xhr.responseText)
rader(jsondata)
}else if(xhr.readyState === 4 && xhr.status===404){
console.log("没有找到这个对象");
}
}
function rader(jsondata){
var html = jsondata.data.list.map(item=>`
<li>
<img src="${item.imageUrl}"/>
<div>${item.name}</div>
</li>
`)
malist.innerHTML = html.join('')
}
}
json部分:
{
"data":{
"list":[
{
"namne":"1111",
"imageUrl":"https://ts1.cn.mm.bing.net/th?id=ORMS.7bf3e9347df69e68f66692e0f32f7bc9&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0"
},
{
"namne":"1111",
"imageUrl":"https://ts1.cn.mm.bing.net/th?id=ORMS.7bf3e9347df69e68f66692e0f32f7bc9&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0"
},
{
"namne":"1111",
"imageUrl":"https://ts1.cn.mm.bing.net/th?id=ORMS.7bf3e9347df69e68f66692e0f32f7bc9&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0"
}
]
}
}
6.2 ajax同步异步
里面的第三个值
xhr.open("GET","http://127.0.0.1:5500/js%E5%AE%9E%E6%88%98%E7%BB%83%E4%B9%A0/data.json",true)
表示异步请求true :表示会进行后面的函数,等返回值调回来的时候跟着回去
false表示同步请求 ::表示异步,要等到返回的数据回来过后才会执行后面的代码,所以容易造成数据的堵塞
6.3 ajax的请求方式
get 偏向获取数据
post 偏向提交数据
put 偏向更新(全部) {name:“kerwin”,age:100]delete 偏向删除信息
patch 偏向部分修改
- get
xhr.open('GET','http://127.0.0.1:8080/server?a=100&b=200');
- post
xhr.open('POST',"http://127.0.0.1:8080/server")
- json
const xhr = new XMLHttpRequest();
//设置响应体数据类型
xhr.responseType='json'
xhr.open('GET','http://127.0.0.1:8080/server-json')
xhr.send()
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
if(xhr.status >= 200 && xhr.status < 300){
// 手动修改
// let data = JSON.parse(xhr.response)
// console.log(data);
//自动修改 在上边设置响应体数据类型
console.log(xhr.response);
}
}
}
6.4 ajax封装
ajax({
ur1:"http://1ocalhost:3000/users",
method:"GET",
async:true ,
data:{
username : "kerwin",
password:"123"
},
headers:{},
success:function(res){
console.log(res)
}
error:function(err){
console.log(err)
}
})
6.6 回调地狱问题
·当一个回调函数嵌套一个回调函数的时候·就会出现一个嵌套结构
·当嵌套的多了就会出现回调地狱的情况·比如我们发送三个ajax请求
.第一个正常发送
.第二个请求需要第一个请求的结果中的某一个值作为参数
.第三个请求需要第二个请求的结果中的某一个值作为参数
6.8 Promise封装ajax
<script>
封装 ajax
function ajax(options) {
let defaultoptions = {
url: "",
method: "GET",
async: true,
data: {},
headers: {
"content-type":"application/x-www-form-urlencoded"
},
success: function () { },
error: function () { }
}
let { url, method, async, data, headers, success, error } = {
...defaultoptions,
...options
}
</script>
6.10 fetch
用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。当遇到网络错误时,fetch() 返回的 promise 会被 reject,并传回 TypeError。成功的 fetch() 检查不仅要包括 promise 被 resolve,还要包括 Response.ok 属性为 true。HTTP 404 状态并不被认为是网络错误。
`
var username = "kerwin"
fetch(` http:// localhost:3000/users111?username=$ {username} `)
.then((res)=>{
console. log(res)
if(res.ok){
return res.json()
}else{
//拒绝
return Promise.reject(
}
cookie
<script>
//cookie 本地存储
// 存cookie
savebtn.onclick = function(){
//路径设置
// document.cookie = "username=xiaoming;path=/155-cookie/aaa"
document.cookie = "age=18"
//过期时间设置
var date = new Date()
date.setMinutes(date.getMinutes()+10)
document.cookie = `username=kerwin;expires=${date.toUTCString()}`
}
getbtn.onclick = function(){
console.log(getCookie("age"))
}
function getCookie(key){
var str = document.cookie
var arr = str.split("; ")
// console.log(arr)
var obj = {}
for(var i=0;i<arr.length;i++){
var subArr = arr[i].split("=")
// console.log(subArr)
obj[subArr[0]] = subArr[1]
}
// console.log(obj)
return obj[key]
}
delbtn.onclick = function(){
var date = new Date()
date.setMinutes(date.getMinutes()-1)
document.cookie = `username=111;expires=${date.toUTCString()}`
document.cookie = `age=111;expires=${date.toUTCString()}`
}
</script>
josnp
注意:
- 后端接口形式必须**(),需要后端配合
- jsonp 缺点
onload 删除sciprt标签
只能get请求,不能post put delete
mybtn.onclick = function(){
var oscript = document.createElement( "script")
oscript.src="01.txt”//未来地址
document.body . appendchild(oscript)
}
闭包
函数内部返回一个函数,被外界所引用。
这个内部函数就不会被销毁回收。
内部函数所用到的外部函数的变量也不会被销毁
闭包案例
- 求索引值下标
法一:(闭包)
var oli = document.querySelectorAl1("li")
for (var i = 0; i < oli.length; i++) {
oli[i].onclick = (function (index) {
return function () {
console.log(11111, index)
}
})(i) //匿名自执行函数
}
法二:(ES6)
var oli = document.querySelectorAl1("li")
for(let i=0;i<oli.length;i++){
oli[i].onclick =function(){
console.log(i)
}
}