javaScript高级

一世执手 提交于 2019-12-27 01:20:15

函数进阶

执行上下文

执行上下文:指的是代码的运行环境。(控制执行顺序

执行上下文的分类:

全局上下文:代码的默认运行环境,代码一旦被加载,就会产生一个全局上下文;

局部上下文:当函数被调用时,就会产生一个局部上下文;

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. 局部刷新页面

  2. 与服务端异步通信

 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();


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!