函数进阶
执行上下文
执行上下文:指的是代码的运行环境。(控制执行顺序)
执行上下文的分类:
全局上下文:代码的默认运行环境,代码一旦被加载,就会产生一个全局上下文;
局部上下文:当函数被调用时,就会产生一个局部上下文;
eval 上下文(仅作了解) 如eval('console.log("hello")');可以解析代码,正常执行
1 执行上下文保存在栈里,全局上下文先进后出(压栈/出栈)
2 每一个上下文产生,就开始执行代码,代码执行完成就出栈
3 全局上下文在浏览器关闭后出栈
4 处于活动状态的上下文永远在最上面
案列分析:
function add(min, max) {
if (min === max) {
return max;
}
return min + add(min + 1, max);
}
console.log(add(1, 3));
此代码,先保存函数地址,再输出语句中调用函数add(1,3)
进入函数体中,找到函数add(2,3);
再调用函数add(2,3),再找到函数add(3,3)
然后运行函数。ad(3,3)返回 3
add(2,3)返回2+3
add(1,3)返回1+2+3 所以输出为6
function foo1() {
console.log('foo1');
foo2();
}
function foo2() {
console.log('foo2');
}
foo1();
(function () {
})()
//fool foo2
变量对象
Variable Object (VO)
在创建执行上下文阶段,会经历以下三件事:
1. 创建变量对象
2. 建立作用域链
3. 确定 this 的指向
在创建变量对象的过程中,需要做三件事:
1. 查找当前作用域中所有的参数
2. 查找当前作用域中所有的声明式函数
3. 查找当前作用域中所有 var 声明的变量
function foo(a) {
console.log(a);
console.log(b);
var b = 2;
}
foo(1);
输出为:1 undefined
var a = 1;
function b() {
console.log(a); //1
a = 2;
console.log(a); //2
a = 3;
console.log(a); // 3
}
console.log(a); //1
b();
console.log(a); // 3
作用域链
由当前上下文和上层上下文中一系列的变量对象组成。
看在哪里声明的就找那一层,作用域再函数声明时产生(控制作用域)
var a = 1;
function foo() {
b = 10;
return;
function a() {}
}
foo();
console.log(b);//输出10
function abc(num) {
if(num > 3) {
abc(--num);
}
console.log(num);
}
abc(5);
先保存函数地址。再调用函数add(5);找到函数add(4);找到函数add(3);执行代码,先进后出。所以依次输出3,3,4
var a = 1;
function foo() {
b = 10;
return;
function a() {}
}
foo();
console.log(b);//输出10
function foo1() {
var a = 1;
console.log(a);//1
function foo2() {
var b = 2;
console.log(a + b);//3
function foo3() {
var c = 3;
console.log(a + b + c);//6
}
foo3();
}
foo2();
}
foo1(); //
闭包(closure)
可以再谷歌浏览器中查看到
该销毁时没有销毁,后面需要时再参与运用。
缺点:占用内存
优点:1 延长了局部变量的使用时间 2 避免变量污染(重名)
var a = 1;
function foo() {
console.log(a);
}
(function () {
var a = 2;
foo();
})();
输出为1
看在哪里声明的就找那一层,作用域再函数**声明**时产生
function foo() {
var a = 10;
function bar() {
console.log(a);
}
return bar;
}
var baz = foo();
baz();
输出为10;
先把储存foo()函数,再把foo()存储在baz中,调用函数,函数执行后销毁,但会保存a的数据,后面再次调用时会拿来用,用完再销毁,所以输出为10;
面试题目
const lis = document.querySelectorAll("li");
for (var i = 0; i < lis.length; i++) {
(function (i) {
lis[i].onclick = function () {
console.log(i);
}
})(i);
}
输出全是5。
因为最后取值为5,会一直保存这个5的数据,会覆盖之前的值。
此时应该在循环体中添加以下等等。或者let i=0;
(function (1) {
lis[i].onclick = function () {
console.log(i);
}
})(1);
(function (2) {
lis[i].onclick = function () {
console.log(i);
}
})(2);
(function (3) {
lis[i].onclick = function () {
console.log(i);
}
})(3);......
编程范式
编程范式:指写代码的风格或模式
命令式编程
1 面向过程(用函数做封装)
2 面向对象 重点:对象 (游戏)
类:类是对象的一种抽象概括,对象是类的一种具体实现
面向对象的三大特征:1 封装 2 继承 3 多态
封装:(一个对象就是一个封装,属性,方法)
构造函数
创建函数,函数名首字母大写
如:
function Student(name) {
this.name = name;
this.age = "20";
this.gender = "male";
this.sayHello = function() {
console.log("hello");
}
}
let s1 = new Student("zhangsan");
let s2 = new Student("lisi");
let s3 = new Student("wangwu");
console.log(s1, s2, s3);
s1.sayHello();
为了多次调用,需传参
构造函数:看调用时是否有new
原型模式
优点:内存占用只在原型
function Student(){};
Student.prototye.name = name;
Student.prototye.age = "20";
Student.prototye.gender = "male";
Student.prototye.sayHello = function(){
console.log("hello")
}
let s1 = new Student;
let s2 = new Student;
let s3 = new Student;
console.log(s1.name,s2.age,s3.gender);
s1.satHello();
混合模式
(属性写在构造函数,方法写在原型模式)
function Student(){
this.name = name;
this.age = "20";
this.gender = "male";
}
Student.prototye.sayHello = function(){
console.log("hello");
}
const s1 = new Student("zhangsan");
console.log(s1);
s1.satHello();
将方法用到原型上,属性写在对象上
ES6 类 class
//class 跟上类的名字,自命名
class Student {
//固定格式constructor
//括号内的name 是形参
constructor(name){
this.name = name;
this.age = "20";
this.gender = "male";
}
sayHello(){
console.log("hello");
}
//在类里面访问自己的属性或方法 直接可以通过this.属性/方法 来获取
//当出了类的范围 需要访问时 只能通过对象.来获取
introduce(){
console.log("我叫" + this.name);
}
}
//括号内的 zhangsan 是实参
//实例对象
const s1 = new Student("zhangsan");
console.log(s1);
s1.sayHello();
new 关键字
new 关键字在构造函数背后做的四件事情:
1. 在函数内部创建一个空对象
2. 将该对象的`__proto __` (proto 前后各有2个下划线) 属性指向构造函数的 prototype 属性
3. 执行构造函数的代码,并且将 this 指向该对象
4. 返回该对象
实例对象:通过构造函数构造出来的对象
构造函数/类 里面的所有this 都指向的是实例对象,只有调用后才指向
概念**:
1 每一个函数身上都有一个prototye
属性,叫原型(原型对象)
2 每一个对象身上都有一个__proto __
属性,叫做隐式原型
3 每一个对象身上的__proto __
,指向构造该对象的函数的 prototye
prototye的类型是对象
__proto __
(proto前后各有2个下划线)
console.log(foo instanceof Object)问该数据是不是一个对象
返回true或者false;
function Foo(){}
let f=new Foo();
console.log(Foo.prototype);<==>console.log(f.__proto__);
4 每一个函数本质上都可以看做是由 Function 构造出来的
Foo.__proto__<==>Function.prototype
let new Function()=function(){};
5 每一个对象本质上都可以看做是由 Object 构造出来的
console.log( Object.prototye.`__proti__ `) // null
原型链
当我们访问实例对象的某个属性时,解析器会执行一次搜索:
首先从实例对象开始,如果在实例中找到了该属性,则直接返回对应的属性值
如果在实例中没有找到该属性,就会沿着__proti__
找到它指向的prototye
原型 对象
然后在原型对象中找到该属性,并得到该对应的属性值,这就是原型链
this 指向总结
默认
在函数以外
this指向全局对象(取决于运行环境,浏览器中的全局对象是window)
在函数以内
普通函数
function foo(){console.log(this);}; foo();
this指向全局对象
对象的方法
let obj = {
name:"zhangsan",
//简写ES6 nayName:function(){}
nayName(){
console.log(this);
}
}
this指向调用该方法的对象(点前面的对象)
如:let obj2={};
obj2.sayName=obj.sayName;
obj2.sayName(); this 指向obj2
事件处理函数
this指向事件源(绑定事件的元素节点)
构造函数
this指向 new 出来的实例对象(只有调用时才能确定this指向谁)
改变 this 的指向
call ( ) apply( ) bind( )
// let obj1 = {
// name: 'zhangsan',
// sayName(a, b) {
// console.log(this.name, a, b);
// }
// }
// let obj2 = { name: 'lisi' };
// obj1.sayName.call(obj2, 10, 20);
// obj1.sayName.apply(obj2, [10, 20]);
// let newSayName = obj1.sayName.bind(obj2);
// newSayName(10, 20);等同于以下代码
// obj1.sayName.bind(obj2)(10, 20);
箭头函数
箭头函数没有自己的this,如果在箭头函数内部访问this,实际上访问的是该箭头函数父级(箭头函数声明时所在的父级)的this
继承
继承:一个类继承另一个类的属性和方法(同时又有自己的属性和方法)
class Parent {
constructor(name, gender) {
this.name = name;
this.gender = gender;
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(name, age, gender) {
super(name, gender);//参要一致
this.age = age;
}
}
let c = new Child("lisi", "20", "male");
console.log(c);
let p = new Parent("zhangsan");
console.log(p);
c.sayName();
p.sayName();//调用方法
数据属性
对象里如果添加一条属性,放置被修改,覆盖
可用
let student = {
name: 'zhangsan'
};
student.age = 20;
Object.defineProperty(student(对象名), "gender"("属性名"), {
value: "male ,//value: "属性值"
configurable: true, // 能否被删除,默认 false,不可删除
writable: true, // 能否被修改,默认 false,不可修改
// enumerable: true // 能否被遍历,默认 false,不可遍历
});
添加: student.age = 30;
student.gender = "female";
删除: delete student.gender;
遍历: for (let key in student) {
console.log(student[key]);
}//获取属性值
多种数据防修改的另一种方式
Object.defineProperties(student, {
"gender": {
value: "male",
configurable: true, // 能否被删除,默认 false,不可删除
writable: true, // 能
},
"": { }
})
访问器属性
监听数据变化,及时更新页面数据
let student = {};
let name = "zhangsan";
Object.defineProperty(student, "name", {
set(param//形参) {
name = param;【设置属性调用】
},
get() {
return name;
}【获取属性时调用】
})
student.name = "lisi";
console.log(student.name);
浅拷贝
let arr=[1,2,3]; let Arr=arr;(赋值后互相影响,新数组的地址不会被改变,还是旧数组的)
深拷贝
赋值后,旧的址不会受到影响
Json的两种方法
let arr=[1,2,3]
let str = JSON.stringify(arr);
let newArr = JSON.parse(str);//可以嵌套多层
arr[0] = "a";
arr[2].num = "b";
console.log(arr, newArr);//[a,2,3],[1,2,3]
assign
let newArr = Object.assign([], arr);
只能进行一层的深拷贝,相比json来说不好用
面试题
自己封装一个函数来实现深拷贝
function deepClone(data) {
先判断其数据类型 如数组
// if(data instanceof Array) {}
if (Array.isArray(data)) {
如果为对象
} else if (typeof data === 'object') {
let newData = {};
for (let key in data) {
// deepClone("zhangsan");
// deepClone({num: 20});
newData[key] = deepClone(data[key]);
}
return newData;
}
return data;
}
let newStudent = deepClone(student);
newStudent.name = "lisi";
student.age.num = "18";
console.log(student, newStudent);
Html5
拖拽
一般图片和文字在页面都是可以拖拽的。有些却不行
为了实现拖拽效果,可以添加draggable="true"属性。
<div id="box" class="hezi" draggable="true"></div>
被拖拽元素
身上可以有以下属性
ondragstart:拖拽时一瞬间的事件
ondragend:拖拽结束发生的事件
ondrag:拖拽的过程中发生的事件
投放区元素
被拖拽的元素最后放在的一个元素身上
ondragenter:看鼠标是否进入,鼠标进入则触发
ondragleave:离开
ondragover:在投放区里拖拽的时候触发的事件
ondrop:在鼠标松开时触发,ondragover的一个默认行为会影响到ondrop的发生,一般只需写ondrop时,都需要写ondragover的阻止默认行为
event.preventdefault();
1如代码将一个div移动到另一个div里
2在页面中拖动div
const icon = document.getElementById(`icon`);
const box1 = document.getElementById(`box1`);
const box2 = document.getElementById(`box2`);
// 被拖拽元素
icon.ondragstart = function () {
icon.style.backgroundColor = "green";
}
icon.ondragend = function () {
icon.style.backgroundColor = "yellow";
}
icon.ondrag = function () {
icon.style.border = `2px solid`;
}
// 投放区
box2.ondragenter = function () {
icon.style.backgroundColor = "grey";
}
box2.ondragleave = function () {
icon.style.backgroundColor = "blue";
}
box2.ondragover = function (event1) {
event1.preventDefault();
}
box2.ondrop = function () {
box2.appendChild(icon);
}
// 屏幕中拖
// 获取鼠标在页面的点
const box = document.getElementById(`box`);
let boxx=box.offsetWidth;
let boxy=box.offsetHeight;
box.ondragend = function (event) {
let a=event.clientX;
let b=event.clientY;
box.style.top=b-boxy/2+"px";
box.style.left=a-boxx/2+"px";
}
画布canvas
<canvas id="cvs" width="600" height="600"></canvas>
在html标签中设置宽高(不在css中设置)增加的是像素点
先获取到画布
const cvs = document.getElementById("cvs");
获取画笔 画布.getContext("2d")
const ctx = cvs.getContext("2d");
矩形
(坐标x,坐标y,宽,高)
实心矩形:ctx.fillRect(100, 100, 100, 100)起始坐标为画布的左上角
空心矩形:ctx.strockRect(150, 150, 100, 100)
普通没有任何样式的矩形,包括颜色与边框.需自己后期添加:ctx.rect()
ctx.clearRect(0, 0, cvs.width, cvs.height);全擦除。(样式路径仍然保存)
给图形画边框:ctx.stroke();
图形填充:ctx.fill();
画线条
起点:ctx.moveTo(x方向值,y方向值);
下一个点ctx.lineTo(x方向值,y方向值);
描边:ctx.stroke();
实现闭合,不许要连接左后一点:ctx.closePath();
清空路径容器
ctx.beginPath();
清空前面图形的路径,(画任何图都需要添加)
防止fill和stroke的互相影响,不能改变fillStyle;
如:
ctx.beginPath();
ctx.moveTo(300, 300);
ctx.lineTo(300, 400);
ctx.lineTo(400, 400);
ctx.closePath();
ctx.fill();
样式
ctx.fillText("Hello World",10,50);//添加文本
ctx.font="30px Arial";//文本样式
ctx.strokeText("Hello World",10,50);//空心的文本
ctx.fillStyle="orange";
ctx.strokeStyle="green";
ctx.lineWidth=10; 边框宽度,原点在一半的位置
ctx.lineJoin="round"(圆角) bevel(斜角) miter(直角)
ctx.lineCap="round"(线的两端圆角)
将图片放上画布
var img=document.getElementById("scream");
ctx.drawImage(img,10,10);
固定语句
ctx.save();//保存默认样式---->操作样式
ctx.fillStyle="orange";
ctx.beginPath()------->清空路径
ctx.fillRect(10, 10, 100, 100);
ctx.restore()------->操作样式。拿出默认值
圆
画布节点.arc(坐标x,坐标y,圆半径,起始度,结束度,方向);
坐标x,坐标y即为圆心的坐标
起始度和结束度为弧度:弧度=Math.PI/180*角度
方向:默认False顺时针,true为逆时针
实心或者空心:fillRect();strokeRect();
如需画半圆需要闭合图形
ctx.closePath();
一般也许画图形三步骤,如代码:
ctx.save();
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(300, 300, 100, Math.PI / 180 * 270, Math.PI / 180 * 90, true);
ctx.fill();
ctx.restore();
曲线
画布节点.arcTo();
//先定一个起点
画布节点.moveTo();
画布节点.arcTo(200,200,300,100,200);
//前两个值表示第一个坐标点,接下来的两个值表示第二个点。
// 最后一个值表示弯曲程度
//然后描线
ctx.stroke();
二次贝塞尔曲线
ctx(画布节点).quadraticCurveTo();
// ctx.save();
// ctx.beginPath();
// ctx.moveTo(100, 100);
// ctx.quadraticCurveTo(200, 200, 300, 100);
// ctx.stroke();
// ctx.restore();
三次贝塞尔曲线
ctx(画布节点).bezierCurveTo();取点 三组点
ctx.save();
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.bezierCurveTo(200, 300, 300, 0, 400, 200);
ctx.stroke();
ctx.restore();
转换
移动
画布节点.translate(100, 100);把画布的原点移到给的值范围。多次使用则叠加,后面所有元素都有移动。所以放在 画布节点.save()和 画布节点.restore()中可以限制,让画布回到初始状态.
ctx.save()
ctx.translate(100, 100);
ctx.fillRect(0, 0, 100, 100);
ctx.restore();
放大/缩小
小于1则缩小,是画布在放大,中心点在画布左上角
//缩小 ctx.scale(0.5, 0.5);
//放大 ctx.scale(2, 2);
旋转
ctx.rotate(弧度数);弧度数=Math.PI/180*角度
相当于画布的原点中心旋转,与translate()有关,会改变原点位置
ctx.translate(150, 150);//只能作用与它后面的元素
ctx.rotate(Math.PI / 180 * 45);
ctx.fillRect(-50, -50, 100, 100);
如代码是让一个矩形在画布中心旋转
let deg = 0;
setInterval(() => {
ctx.clearRect(0, 0, cvs.width, cvs.height);
deg++;
ctx.save();
ctx.translate(300, 300);
ctx.rotate(Math.PI / 180 * deg);
ctx.beginPath();
ctx.fillRect(-50, -50, 100, 100);
ctx.restore();
}, 10);
SVG
可伸缩的矢量图形
Scalable Vector Graphics
位图:由像素点构成
矢量图:不会失真,色彩单一。图像在放大或改变尺寸的情况下其图形质量不会有所损失
如需设置样式,还是须在html标签中设置内嵌样式。
<svg width="400" height="100" id="code"> </svg>
SVG有一些预定义的形状元素,可被开发者使用和操作:
可以是单标签或者双标签。不能使用dom方法获取节点添加样式
矩形 <rect>
圆形 <circle>
椭圆 <ellipse>
线 <line>
折线 <polyline>
多边形 <polygon>
路径 <path>
SVG 矩形
<rect width="300" height="100"
style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)"/>
rect 元素的 width 和 height 属性可定义矩形的高度和宽度
style 属性用来定义 CSS 属性
CSS 的 fill 属性定义矩形的填充颜色(rgb 值、颜色名或者十六进制值)
CSS 的 stroke-width 属性定义矩形边框的宽度
CSS 的 stroke 属性定义矩形边框的颜色
创建一个圆角矩形:
<rect x="50" y="20" rx="20" ry="20" width="150" height="150"
style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/>
CSS opacity 属性用于定义了元素的透明值 (范围: 0 到 1)。
rx 和 ry 属性可使矩形产生圆角。
SVG 圆形
<circle cx="100" cy="50" r="40" stroke="black"
stroke-width="2" fill="red"/>
cx和cy属性定义圆点的x和y坐标。如果省略cx和cy,圆的中心会被设置为(0, 0)
r属性定义圆的半径
SVG 椭圆
椭圆与圆很相似。不同之处在于椭圆有不同的x和y半径,而圆的x和y半径是相同的:
<ellipse cx="300" cy="80" rx="100" ry="50"
style="fill:yellow;stroke:purple;stroke-width:2"/>
CX属性定义的椭圆中心的x坐标
CY属性定义的椭圆中心的y坐标
RX属性定义的水平半径
RY属性定义的垂直半径
SVG 直线
<line x1="0" y1="0" x2="200" y2="200"
style="stroke:rgb(255,0,0);stroke-width:2"/>
x1 属性在 x 轴定义线条的开始
y1 属性在 y 轴定义线条的开始
x2 属性在 x 轴定义线条的结束
y2 属性在 y 轴定义线条的结束
SVG 与 Canvas两者间的区别
SVG 是一种使用 XML 描述 2D 图形的语言。
Canvas 通过 JavaScript 来绘制 2D 图形。
SVG 基于 XML,这意味着 SVG DOM 中的每个元素都是可用的。您可以为某个元素附加 JavaScript 事件处理器。
在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。
Canvas 是逐像素进行渲染的。在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,包括任何或许已被图形覆盖的对象。
本地存储
localStorage:永久性的本地存储,能跨窗口
sessionStorage:会话级别的本地存储,窗口关闭后即消失,不能跨窗口
localStorage.getItem("username"【键名】);获取<==>localStorage.username=name;
localStorage.setItem("username", name【"键名":"键值"】);
localStorage.removeItem("username"【"键名"】);删除
localStorage.clear();清空,清除
本地存储,永远是字符串,如果是复杂类型需要转换
let arr = [{ name: 'zhangsan' }];
localStorage.users = JSON.stringify(arr);
console.log(JSON.parse(localStorage.users));
总结
1. 存储空间:
cookie:4KB
本地储存:localStorage、sessionStorage:5M
2. 有效期:
localStorage:永久性
sessionStorage:当前窗口关闭前有效
cookie:默认当前窗口关闭前有效,可手动设置有效期
3.与服务端通信:
cookie:每次请求都会携带 cookie
localStorage、sessionStorage:仅在客户端做数据存储,不参与服务端通信
异步编程
js环境只有一个运行流程环境。
异步:能同时进行。与位置无关。(比如时间函数)
同步:不能同时进行
AJAX(阿贾克斯):Asynchronous JavaScript and XML
-
局部刷新页面
-
与服务端异步通信
1. 创建 XHR 对象
let xhr = new XMLHttpRequest();
2. 打开链接
xhr.open("GET/POST", url, true/false);
xhr.open("GET", "./data.json?id=1&num=2");
3. 发送请求
Get方式
xhr.open("GET", "./data.json?id=1&num=2");
xhr.send();
post方式
xhr.open("POST", "./data.json");
xhr.send("id=1&num=2");
考虑安全与敏感性,一般用post
4. 处理服务端返回的消息
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
4开头为前端错误, 5开头为后端代码错误
封装成函数
// ajax
function ajax({ type = "GET", url, data, success }) {
let xhr = new XMLHttpRequest();
xhr.open(type, url);
xhr.send(data);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
let msg = JSON.parse(xhr.responseText);
success(msg);
}
}
}
在script中写
ajax({ url: '../data/students.json',
type: 'GET',
data: ``,
success(msg) {
console.log(msg);
}
})
注:
0: 请求未初始化,send 还未调用;
1: 与服务器连接建立,send 调用;
2: 请求已接收,send 调用完成;
3: 请求处理中;
4: 请求已完成;
把"id=1&num=2"转化为["id", "1"]
// ajax 数据格式的转换 id=1&num=2 {id:1, num:2}
function parse(data) {
let dataObj = {};
let dataArr = data.split("&"); // ["id=1", "num=2"]
for (let item of dataArr) {
let [key, value] = item.split("="); // ["id", "1"]
dataObj[key] = value;
}
return dataObj;
}
mock
生成随机数据,拦截ajax的请求
生成随机数据
let data = Mock.mock({
//随机生成10到100条内的学生数据对象
"students|10-100": [{
"id|+1": 1,//id升序排序
"name": '@cname()',
"age|18-30": 1,
"gender|1": ["男", "女"],
"address": '@county(true)',
"birth": '@date()',
"phone": /^1[358]\d{9}$/
}]
});
// 拦截 ajax 请求,并返回随机数据
1 Mock.mock( template )
Mock.mock(/\/getStudent/, { /\/ 此处是将//进行转化。
// 生成10-100个对象。
"students|10-100": [{
// 每个对象有以下属性
数据模板中的每个属性由 3 部分构成:属性名、生成规则、属性值:
"id|+1": 1,
"name": '@cname()',
"age|18-30": 1,
"gender|1": ["男", "女"],
"address": '@county(true)',
属性值 中可以含有 @占位符
"birth": '@date()',
"phone": /^1[358]\d{9}$/
}]
});
ajax 请求
ajax({
url: '//getStudent',//于moke一致
success(msg) {
console.log(msg);
}
})
2 Mock.mock( rurl, rtype, function( options ) )
记录用于生成响应数据的函数。当拦截到匹配 rurl 和 rtype 的 Ajax 请求时,函数 function(options) 将被执行,并把执行结果作为响应数据返回。
Mock.mock(/\/register/, "post", options => {
// 获取前端传递过来的数据
let data = parse(options.body);
上句也可以简写成箭头函数 ({body}) => { let data = parse(body);}
// 将数据保存至本地存储中
// 1. 先获取注册好的旧数据
let usersData = getStorage("users");
// 2. 将新数据添加至旧数据中
usersData.push(data);
// 3. 将更新后的数据存储进本地存储中
setStorage("users", usersData);
return true;
})
btn.onclick = function () {
ajax({
type: 'POST',
url: '/register',
data: `username=${username.value}&password=${password.value}`,
success(msg) {
if (msg) {
text2.innerHTML="注册成功!!!";
}
}
})
}
Mock.mock( rurl, rtype, function( options ) )
rurl
可选。
表示需要拦截的 URL,可以是 URL 字符串或 URL 正则。例如 /\/domain\/list\.json/、'/domian/list.json'。
rtype
可选。
表示需要拦截的 Ajax 请求类型。例如 GET、POST、PUT、DELETE 等。
template
可选。
表示数据模板,可以是对象或字符串。例如 { 'data|1-10':[{}] }、'@EMAIL'。
function(options)
可选。表示用于生成响应数据的函数。
options
指向本次请求的 Ajax 选项集,含有 url、type 和 body 三个属性,
ES6处理异步操作
promise
解决回调地狱问题:比如ajax的嵌套问题
promise属于构造函数
new Promise((resolve(成功), reject(失败)) => {//处理的状态
异步代码
if (/* 异步处理成功 */) {
resolve();---->括号内返回结果
} else {
reject();
}
});
let p = new Promise((resolve, reject) => {ajax(
success(msg) {
如果:
resolve(student);
)}
p.then((student) => {
return new Promise((resolve, reject) => {ajax(
success(msg) {
如果:
resolve(classes);
)}
注:then()里的值是resolve()里对应的值
为了不使用变量接受new的promise函数,可以直接拿返回值
return new promise((resolve,reject)=>{异步代码})
后面直接.then(()=>{}).then~即可
new Promise((resolve, reject) => {
}).then(() => {
return new Promise((resolve, reject) => {
})
}).then(() => {
return new Promise((resolve, reject) => {
})
}).then(() => {
}).then(() => {
}).then(() => {
}).then(() => {
})
Generator 函数
Generator 函数
function* myGenerator() {
yield;//执行到该处结束
console.log(a);
let b = yield "b";
console.log(b);
}
let mg = myGenerator();
mg.next();//获取
lmg.next(2);//找第一个yield后再执行之后代码,直到找到下一个yield结束
let n1 = mg.next();//1,n1是对象,有两个值 value,done
(done的值 是否执行完false/true)
let n2 = mg.next(2);//2,next()里可传值,第二个next传的是第一个 yield的值 let a = yield "a"
ES7异步终极解决方案
async、await
1 async定义一个异步函数
2 await等待 1 promise对象 2 等待一个异步操作的结果,只能用在异步函数 内部
async function foo(){} 封装异步函数,放在async中
let name = "张三";
// 请求学生
function getStudent() {
return new Promise((resolve, reject) => {
ajax({
url: `../lesson13/data/students.json?name=${name}`,
success(msg) {
let [student] = msg.filter(item => item.name === name);
resolve(student);
}
})
})
}
// 请求班级
function getClass(student) {
return new Promise((resolve, reject) => {
ajax({
url: `../lesson13/data/classes.json?classId=${student.classId}`,
success(msg) {
let [classes] = msg.filter(item => item.id === student.classId);
// console.log(classes);
resolve(classes);
}
})
})
}
// 请求教师
function getTeacher(classes) {
return new Promise((resolve, reject) => {
ajax({
url: `../lesson13/data/teachers.json?teacherId=${classes.teacherId}`,
success(teacher) {
resolve(teacher)
}
})
})
}
async function main() {
const student = await getStudent();
const classes = await getClass(student);
const teacher = await getTeacher(classes);
console.log(student, classes, teacher);
}
main();
来源:CSDN
作者:weixin_45435854
链接:https://blog.csdn.net/weixin_45435854/article/details/103718276