三阶段整理

day01 - JS高级语法(一)

01 - 全局变量_局部变量
  • 定义:
    1. 定义在function外部的变量:全局变量
    2. 定义在function内部的变量:局部变量
    3. 定义在function内部,但没有var的变量也是,适合公用的变量
  • 使用场景
    • 全局:很少,一直常驻内存中不易销毁,容易出现命名冲突,适合公用的变量
    • 局部:函数执行完毕
02 - 作用域链
        var point = 30;
        function play() {
            //就近原则:从内部开始寻找,如果找不到再去外层作用域查找
            var point2 = 20;
            alert(point);
        }
        play();//30
  • 作用域
    • 函数作用域:函数内部使用范围
    • 全局作用域:整个网页范围
03 - 提前声明
        function fn(a) {
            console.log(a);//function(){} 优先级高
            var a = 2;
            function a() { }
            console.log(a);//2
        }
        fn(1);

        // 优先显示function a() { }
04 - 经典面试题
        for(var i=1;i<=3;i++){
            //定时器异步执行,等外部代码全部执行完毕再执行自己
            setTimeout(function(){
                alert(i);
            },0)
        }        

        for(let i=1;i<=3;i++){
            //let 在每次循环的时候,创建了一个变量副本, 并且保留下来
            setTimeout(function(){
                alert(i);
            },0)
        } 

        // 输出,4 4 4 1 2 3
05 - let
  • 特点:
    1. 块级作用域,就是大括号
    2. 暂时性死区【不能在初始化之前访问它】
    3. 当全局变量使用的时候,它不属于window对象了
        //let:新增了块级作用域,就是大括号
        function play(){
            let a=10;
            if(1==1){
                let a=20;
                {
                    let a = 30;
                    console.log(a);
                }
                console.log(a);
            }
            console.log(a);
        }

        function run(){
            //不能在初始化之前去访问let修饰的变量:暂时性死区
            console.log(x); //Cannot access 'x' before initialization
            let x=66;
        }

        var global_name = 'frank'
        let global_age = 19
        //用let定义的全局变量,不属于window,用var定义的全局变量是属于window的
        console.log(window.global_name);
        console.log(window.global_age); // 拿不到

        run();	// 报错
        play();	// 30,20,10
06 - const
  • const【常量】
  • 命名:要求全部大写,多个单词之间用下划线隔开
  • 特点:
    1. 定义的时候就得初始化它的值,且后面不能修改
    2. 当作局部变量的时候,效果和let一样
    3. 如果用const定义一个对象,那么时可以修改对象内部属性的
        //常量:定义的时候就得初始化它的值,且后面不能再修改
        const IP_ADDRESS = '172.168.2.1';
        // IP_ADDRESS="127.0.0.1"; 错误的
        //如果要将const当成局部变量去使用,则特点和let一样的
        if(1==1){
            const ONE=1;
        }
        console.log(ONE); //报错:ONE is not defined
07 - 定时器面试题(定时器是异步执行的他比同步执行的慢)
        console.log(3)
        setTimeout(function(){
            console.log(1)
        },0)
        console.log(4)
        setTimeout(function(){
            console.log(2);
        },0)
        console.log(5)
        //3,4,5,1,2
08 - const问题
        //如果用const定义一个对象,那么是可以修改对象内部属性的
        const OBJ={name:'jackie',age:30};
        OBJ={};
        OBJ.name='rose';
09 - 匿名函数
10 - IIFE
  • IIFE(立即执行函数表达式)

  • 语法:

    • (function([形参列表]){ //函数体(立即执行的JS代码) [return] })([实参列表])
  • 作用:

    1. 早期模块化解决方案,避免了命名冲突

    2. 防止外部代码来访问我内部的一些变量,提高了安全性

      注意:连续写多个IIFE会报错,请使用分号隔开

11 - IIFE
12 - 闭包
  • 定义:
    • 函数嵌套函数,内部函数可以访问外部函数的局部变量,闭包环境是内部函数和外部函数沟通的桥梁。
  • 好处:
    • 内部变量既有了全局变量的常驻内存不销毁的特点,并且不会和外部名称重名
  • 坏处:
    • 用多了之后,增加了内存消耗,容易造成内存泄漏
  • 原理:
    • 局部变量一直被内部函数所使用,所以不会被垃圾回收器收走
        var fn = (function(){
            var num=10;
            return function(){
                num++;
                console.log(num);
            }
        })()
        //闭包:函数嵌套函数,内部函数可以访问外部函数的局部变量,闭包环境是内部函数和外部函数沟通的桥梁
        //在外部执行fn,不论执行多少次,num变量一直存在,从未还原过
        //好处:num既有了全局变量的常驻内存不销毁的特点,并且num又不会和外部名称重名
        //坏处:用多了之后,增加了内存消耗,容易造成内存泄漏
        //num为什么不会被num垃圾回收器收走:
        //这个变量一直被内部函数(fn)所使用,所以num不会被垃圾回收器收走
        fn();//11
        fn();//12
        fn();//13
        //如何让GC回收掉num呢?
        //将fn设置为null,没有地方用num了,自然就被GC收走了
        fn=null;

        //没有任何地方使用的变量,会被垃圾回收器收走(释放内存空间)
        var s="jackie";
13 - 闭包应用
    //点击LI,弹出LI的下标
    let lis = document.querySelectorAll('li')
    for(var i=0;i<lis.length;i++){
        (function(s){
            lis[s].onclick=function(){
                alert(s);
            }
        })(i)
    }

14 - 闭包面试题
        var name = "The Window";
        let object = {
            name: "My Object",
            getNameFunc: function () {
                console.log(this);
                var that = this;//that就是object
                return function () {
                    console.log(this);//此时this已经变化为window了,所以不要用this
                    return that.name;//object.name
                };
                //独立的创建一个函数,不论写在哪,都属于window
                function play(){
                    console.log("play 里面的this是谁呢?",this);//window
                }
                var run =function(){
                    console.log("run 里面的this是谁呢?",this);//window
                }
                run();
                play();
            }
        };
        object.getNameFunc()();

15 - this
        var obj = {
            start:function(){
                console.log(this);
            }
        }
        obj.start();//obj
        var fn = obj.start;
        fn();//windows

  • this指向问题

    • this指向window

      • function 函数名(){}
        var 函数名=function(){}
        
        
    • this指向当前这个对象

      • var obj = {
        函数名:function(){}
        }
        
        
    • this指向当前这个btn按钮

      • btn.onclick=function(){}
        
        
16 - arguments
  • arguments
    • 含义:当前函数的实参列表(只能在函数里面使用)
  • arguments.callee
    • 含义:当前函数(只能在函数里面使用)
17 - call_apply
  • 相同点:都是调用函数,并且动态修改函数里面的this值
  • 不同点:
    • 函数名:call(新this值,参数1,参数2,参数N)
    • 函数名:apply(新this值,[参数1,参数2,参数N])
  • 场景:
      //slice截取的时候,找的是 this
      let args = [7,8,9].slice();//还是7,8,9 从原数组截取的
      let args = [7,8,9].slice.call([1,2,3]);//1,2,3,因为修改了this指向,所以从后面这个数组截取的

18 - 函数柯里化
  • 含义:柯里化是一种使用多个参数的一个函数,转换成一系列使用一个参数的函数的技术
  • 意义:通过拆分参数的方式达到减少代码冗余,增加可读性的目的
    function sum(){
    //调用slice方法,但是把slice里面的this改成arguments,然后产生一个新数组
    let args = [].slice.call(arguments);//1,3
    function exec(){
        args.push(...arguments);// args = [1,2,3,4]
        return exec;
    }
    exec.calc=function(){
        return args.reduce(function(total,current){
            return total+current;
        })
    }
    return exec;
}

        function sum(){
            //调用slice方法,但是把slice里面的this改成arguments,然后产生一个新数组
            let args = [].slice.call(arguments);//1,3
            function exec(){
                args.push(...arguments);// args = [1,2,3,4]
                return exec;
            }
            exec.calc=function(){
                return args.reduce(function(total,current){
                    return total+current;
                })
            }
            return exec;
        }
        // console.log(sum(1,3)(2,4)(100)(1));
        var exec1 = sum(1,3);
        var exec2 = exec1(2,4)
        var exec3 = exec2(100)
        var exec4 = exec3(1);
        console.log(exec4.calc());

19 - 函数柯里化简化
        function a(){
            var arr=[];
            var play =  function(num){
                arr.push(num);
                console.log(arr);
                return play;
            }
            return play;
        }
        var play = a()
        var play2 = play(1);
        var play3 = play2(2);
        var play4 = play2(3);

day02 - JS高级语法(二)

01 - 柯里化
        function sum(){
            //1.第一层函数只用来收集参数的,参数10给的是外层函数
            //将伪数组转换为普通数组
            //调用普通数组的slice方法,然后截取的是arguments的值,最终返回一个新数组
            var args = [].slice.call(arguments);//args=[10,1]

            return function(){
                //2.参数20给的是内层函数,并且将10和20合并起来
                args.push(...arguments);//args=[10,1,20,30,40,50]
                var total=0;
                for(var i=0;i<args.length;i++){
                    total+=args[i]
                }
                return total;
            }
        }
        console.log(sum(10,1)(20,30,40,50));

02 - 柯里化
        //普通函数写法
        function validate(reg,str){
            return reg.test(str);
        }
        console.log(validate(/^\d{1,3}$/,"v88"));

        //柯里化函数写法(一个函数只接收一个参数)
        function currying(reg){
            return function(str){
                return reg.test(str);
            }
        }
        var validPhone = currying(/^\d{11}$/)
        var validEmail = currying(/^d2d2d@d$/)
        
        validPhone("123123123")
        validPhone("23533")
        validEmail("12323")

03 - eval
        var str = "1*2+3";
        document.write(eval(str));
		// 太过强大,不建议使用

04 - 递归
  • 执行上下文【代码的执行坏境】

    1. 全局执行上下文
    2. 函数执行上下文
    3. eval执行上下文,[很少使用,了解即可]
  • 执行上下文调用栈【代码的执行流程】【先进后出】

    1. 全局上下文入栈
    2. 函数1上下文入栈
    3. 函数2上下文入栈
    4. 函数N上下文入栈
    5. 函数N上下文出栈
    6. 函数2上下文出栈
    7. 函数1上下文出栈
    8. 全局上下文出栈

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7iKqDl4y-1634128183206)(images/20210907111232.png)]

        var i=1;
        function play(){
            i++;
            if(i==1000){
                return;
            }
            console.log(i,Math.random())
            play();
        }
        play();

  • 递归

    • 含义:函数内部调用自身的过程
    • 特点:
          1. 函数调用函数,执行传递的动作;
          2. 确定最后一次的终止条件,执行回归的动作
    
    
05 - 递归求阶乘
    function  ji(n) {
        if(n == 1)  return 1;   //确定边界,回归
        var  j  =  ji(n  -  1);   //传递
        return  n  *  j;    
    }
    ji(10)

  • 刨析图

    image-20210907111453723
06 - 递归_快速排序
        let arr=[4,7,3,20,11,2];
        function quickSort(list){
            if(list.length==0){
                return list;
            }
            //1.找基准值,就是第一个值
            let basic = list[0];
            let left_arr=[];
            let right_arr=[];
            if(list.length==1){
                return basic;
            }
            //2.遍历数组,从基准值的下一个开始
            for(let i=1;i<list.length;i++){
                if(basic<list[i]){
                    //3.放右边
                    right_arr.push(list[i])
                }
                if(basic>list[i]){
                    //4.放左边
                    left_arr.push(list[i])
                }
            }
            return [].concat(quickSort(left_arr),basic,quickSort(right_arr));
        }
        console.log(quickSort(arr));

  • 递归面试题二【快速排序】

  • 分析思路:

    1. 在数据集之中,选择一个元素作为”基准”

    2. 所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。

    3. 对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

      案例模拟:

      4,7,3,20,11,2
      基准:[3,2],4,[7,20,11]
      [3,2]
      基准:2,[3]
      [3]
      [7,20,11]
      基准:7,[20,11]
      [20,11]
      基准:11,20
      代码实现:

07 - 变量类型
        var a = 123;
        var b = { name: 'jack' }
        function show(x, y) {
            x = 456;
            y = { name: 'rose' }  //更改为新对象的内存地址
            y.name = 'rose'     //修改原对象内部属性
        }
        show(a, b)
        console.log(a, b)

就是存储的值,还是地址的问题

08 - 浅拷贝
  • 对象浅拷贝
    • 概念:复制出来的对象做修改时对原对象造成了影响
    • 写法:
      1. 引用赋值:var 对象B=对象A;
      2. 扩展运算符:var 对象B={…对象A}
      3. Assign :Object.assign(目标对象,源对象);
  • 案例;
        //浅拷贝:复制出来的对象做修改时对原对象造成了影响
        var a ={
            name:'jack',age:30,work:['写代码','开滴滴','跑摩的']
        }
        var b = a; //复制了引用的地址而已【浅拷贝】
        b.name='rose';
        console.log(a.name);//rose

        // 虽然c是新创建的一个对象,c不等于a,
        //但是:展开符只能展开一层,但是a里面还有一个对象,就是work数组
        var c = {...a};
        c.name='peter'
        //c和a是不同的两个对象,但是c和a他们俩共用同一个work
        c.work[0]='项目经理'
        console.log(a.work);//['项目经理','开滴滴','跑摩的']

        var x ={};
        var y={code:'XA003',list:[1,2,3]}
        //将y的全部内容复制到x里【浅拷贝】
        var result = Object.assign(x,y);
        console.log(x);
        x.list.push(4,5,6);
        console.log(y);

09 - 深拷贝
  • 对象深拷贝

    • 概念:复制出来的对象和源对象无任何关系,不会再互相影响,在堆内存中独立存储

    • 写法:

      • 方式一:
        JSON.stringify(源对象)、JSON.parse(源对象JSON字符串)
        缺点:undefined的值、函数无法拷贝

      • 方式二:
        递归深拷贝

            function deepCopy(target,source){
                for(let i in source){
                    if(typeof source[i]=='object'){
                        let p=null;
                        if(source[i].length){
                            //数组
                            p=[];
                        }else{
                            //对象
                            p={};
                        }
                        target[i] = deepCopy(p,source[i])
                    }else{
                        target[i]=source[i];
                    }
                }
                return target;
            }
        
        

day03 - JS高级语法(三)

01 - 二分查找法
  • 前提:有序数组

  • 思路:

    1. 计算出中间值,然后和要查找的数字比较是在中间值的左侧还是右侧

    2. 缩短查找范围,再重新计算中间值,继续判断

    3. 直到要查找的数字就是中间值为止

      代码:

              //1.循环数组,逐个比较
              //2.数组.indexOf(300)
              //3.二分查找法(折半查找法):前提是有序数组
              //寻找数字5的下标是多少?
              var arr =[1,2,3,4,5,6,7,8,9,10,11,12,13,14];
              function binarySearch(arr,num){
                  //1.找出中间值
                  var start = 0;
                  var stop = arr.length-1;
                  var middle = parseInt((stop+start)/2)
                  //2.比较中间值和要查找的数字
                  while(arr[middle]!=num && stop>start){
                      if(arr[middle]<num){
                          //说明我要找的值在右侧
                          start = middle+1;
                      }else{
                          //说明我要找的值在左侧
                          stop = middle-1;
                      }
                      //3.每次循环要重新计算中间值
                      middle = parseInt((stop+start)/2)
                  }
                  return arr[middle]!=num?-1:middle;
              }
              console.log(binarySearch(arr,5));
      
      
02 - 防抖
  • 函数防抖(debounce)
  • 思路:
    • 在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms
    • 如果在200ms内没有再次触发滚动事件,那么就执行函数
    • 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
  • 效果:
    • 如果短时间内大量触发同一事件,只会执行一次函数
  • 实现:
    • 借助定时器完成

代码:

    //滚动时,调用的其实是debounce里面返回的匿名函数
    window.onscroll=debounce();
    
    function debounce(){
        var timer=null;
        //每次滚动的时候,先清除上一次还未执行的定时器,然后再启动新的定时器
        //高频次的滚动,不断的清除定时器,减少了函数的执行次数
        return function(){
            clearTimeout(timer);
            timer = setTimeout(function(){
                var top = document.documentElement.scrollTop || document.body.scrollTop;
                console.log(top);
            },100)
        }
    }

03 - 节流
  • 函数节流(throttle)
  • 问题:
    • 希望即使用户不断拖动滚动条,也能在某个时间间隔之后给出反馈
  • 思路:
    • 连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率,类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活

代码:

    //滚动时,调用的其实是throttle里面返回的匿名函数
    window.onscroll=throttle(500);
    
    function throttle(delay){
        var start=0;//初始化第一次执行的时间点
        return function(){
            //每次滚动时调用内部函数
            var now = Date.now();
            //用当前时间 - 上次执行的时间
            var sub = now - start;
            //计算看是否超过了500毫秒
            if(sub>delay){
                //如果超过了500毫秒,去执行一次代码
                var top = document.documentElement.scrollTop || document.body.scrollTop;
                console.log(top);
                //执行完业务代码之后,将当前时间作为下一次执行的开始时间
                start=now;
            }
        }
    }

04 - 严格模式
  • 注意事项:
    1. “use strict” 指令只允许出现在脚本或函数的开头。
    2. 严格模式下不能使用未声明的变量,不论是局部还是全局。
    3. 在函数内,禁止this关键字指向全局对象
    4. 在函数内,不能使用arguments.callee
      优点:
    5. 消除代码运行的一些不安全之处,保证代码运行的安全;
    6. 提高编译器效率,增加运行速度;
    7. 为未来新版本的Javascript做好铺垫。

代码:

        //如果写在全局,则全局都是严格模式,如果写在函数内,则函数内代码是严格模式
        //一定要写在第一行
        "use strict";
        
        //x="123";  必须使用变量修饰符,否则报错

        function play(){
            console.log(this);//this不再指向全局对象了(window)
        }
        play();

        var obj = {
            sub(){
                //不能使用arguments.callee
                console.log(arguments.callee);
            }
        }
        obj.sub();

05 - 模板字符串
  • ES6【ES2015】

    • ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。
    • JavaScript是对这个标准的实现和扩展
  • 解决2个问题:

    1. 变量和字符串连接的问题,不需要再用加号拼接

    2. 多行字符串不需要再用多组+拼接

      案例:

              var name="科比"
              //模板字符串
              //解决2个问题:
              //1.变量和字符串连接的问题,不需要再用加号拼接
              //2.多行字符串不需要再用多组+拼接
              var str = `${name}是NBA最好的得分手之一,突破、投篮、罚球、三分球他都驾轻就熟
                  几乎没有进攻盲区,单场比赛81分的个人纪录 
                  就有力地证明了这一点。除了疯狂的得分外, 
                  ${name}的组织能力也很出众,经常担任球队进攻的第一发起人。
                  另外${name}还是联盟中最好的防守人之一,贴身防守非常具有压迫性。`
              document.write(str);
      
      
06 - 扩展运算符
  • 【…】

  • 函数中应用:

    • 形参arr的前面写三个点,就代表这个数组的长度是不一定的,你传递的实参数组个数多少都无所谓

          function changeParam(…arr){
              console.log(arr);
          }
          changeParam(“a”,”b”,”c”);
          changeParam(123,456);
          changeParam([“a”]);
      
      
    • 如果还想传别的参数,要记得把可变参数放最后

          function changeParam(num,...arr) {
              console.log(arr+"<br>");
          }
          changeParam(2,["a", "b", "c"]);
          changeParam(3,[123, 456]);
          changeParam(4,["a"]);
      
      
  • 对象中应用:

    • 展开对象的最外层结构

          let z = { a: 3, b: 4 }; 
          let n = { ...z };
      
      
  • 数组中应用:

        //数组转序列
        console.log(...[1, 2, 3]); //1 2 3
        console.log(1, ...[2, 3, 4], 5); //1 2 3 4 5
        //伪数组转化为数组
        var oDiv = document.getElementsByTagName("div");
        console.log([...oDiv]); //[div, div, div]
        //数组复制
        var arr2=[…arr1]
        //求最大值
        Math.max(...array)
    
    
07 - 默认参数
        //旧的默认参数写法
        function sum(x,y){
            x = x || 0;
            y=y  || 0;
            return x*y;
        }
        console.log(sum());

        //ES6的默认参数写法
        //如果传递了参数,则使用传过来的参数;如果没传参数就用默认值 0 
        function multiple(x=0,y=0){
            return x*y;
        }
        console.log(multiple());
        console.log(multiple(1,3));


	//如果传递了参数,则使用传过来的参数;如果没传参数就用默认值
    function show(name = "some people", sex = "man", age = "18") {
        //你的骚操作
    }
    show();
    show("jackie","woman",33)

08 - 解构赋值
    //字符串:"how are you doing?" 将每个单词放在一个单独的变量里
    var str = "how are you doing?" ;
    [one,two,three,four] = str.split(" ")
    console.log(one);
    console.log(two);
    console.log(three);
    console.log(four);
    //可以在对应位置留空来跳过被解构数组中的某些元素
    [,,u,] = str.split(" ")
    console.log(u);
    //结合“扩展运算符”来捕获数组中的所有尾随元素
    [x,...y] = str.split(" ")
    console.log(x);//how
    //y这个变量是否是Array类型的实例
    console.log(y);//Array
    //typeof只能检测出来:string,number,boolean,function,undefined,object
    //instanceof
    console.log(y instanceof Date);//false
    console.log(new Date() instanceof Date);//true
    //面试题:不利用第三个变量交换a和b的值
    var a = 1;
    var b = 3;
    a=a+b;//a=4,b=3
    b=a-b;//a=4,b=1
    a=a-b;//a=3,b=1
    console.log(a,b);
    var a = "Cat";
    var b = "Dog";
    [b,a]=[a,b]
    console.log(a,b);
    //对象的结构
    var animal={
        type:'猫科动物',
        color:'黄色',
        age:3,
        name:'小黄'
    }
    let {type,color} = animal;
    console.log(type);
    console.log(color);
    //对象当参数的结构
    function hunt({name}){
        console.log(name);
    }
    hunt(animal);

09 - Set
  • 含义:一种无序、值必须唯一的数据集合

  • 创建Set集合:可接收数组或类似数组的对象、字符串作为参数
    var myset=new Set([可选参数]);

        //1.创建Set集合
        const myset = new Set();
        //2.给集合添加值
        myset.add(true)
        myset.add("Frank")
        myset.add("Rose")
        myset.add(123)
        myset.add({})
        //3.判断某个值是否存在
        console.log(myset.has("Frank"))
        //4.删除
        myset.delete("Frank")
        console.log(myset.has("Frank"))
        //5.keys()和values()返回所有的数据集合
        console.log(myset.keys());
        console.log(myset.values());
        //6.清空
        // myset.clear();
        // console.log(myset)
        //遍历
        myset.forEach(item=>{
            console.log(item);
        })
        //新增加的for-of遍历语法:这里的i不是下标,而是值
        for(let i of myset){
            console.log(i);
        }
        for(let i of [55,66,77,88,99]){
            console.log(i);
        }
        //面试题:数组去重
        var list = ["jack","rose","Frank","Peter","Tim","rose","Frank"];
        var myset2 = new Set(list)
        //Array.from()可以将伪数组,Set 转换为普通数组
        console.log(Array.from(myset2))
    
        //iterable 可以被遍历的对象
    
    
10 - Map
  • 含义:采用key-value的键值对形式存储数据,key不能重复

  • 创建Map集合:

    • var maps=new Map();

          //1.创建map实例
          var m = new Map();
          //2.给map添加数据
          m.set("name","jackie");
          m.set(100,10000);
          m.set(false,true);
          //3.根据key获取value
          console.log(m.get(100));
          //4.删除
          m.delete(false)
          //5.根据key来判断value是否存在
          console.log(m.has(false));
          //6.返回map里所有的key
          console.log(m.keys());
          //7.返回map里所有的value
          console.log(m.values());
          //8.返回map里所有key-value数据对
          console.log(m.entries());
          //9.遍历
          m.forEach(function(value,key){
              console.log(key,value);
          })
          //10.遍历
          for(let i of m){
              console.log(i)
          }
          //清空
          m.clear();
      
      
扩展:数组、Set、Map 对比
Array有序集合下标唯一,值可重复,下标是有序的
Set无序集合没有下标,值是唯一
Map无序集合键值对存储键唯一,值可重复

day04 - 面向对象(一)

面向对象编程(OOP)
  • 意义:使用对象时,只关注对象提供的功能,不关注其内部细节

  • 创建:

        //字面量方式创建对象:
        var obj = {
            'sex':'女',  //1.添加属性  描述
            //2.添加方法  行为
            buy:function () {
                    console.log('买搓衣板');
            }
        }
    
    
        //实例创建对象:(代码冗余)
        var obj = new Object();
        //1.添加属性
        obj.name = '小华';
        //2.添加方法
        obj.skill = function () {
            console.log('敲代码');
        }
    
    
        //工厂模式创建对象:(缺点:结构不明确)
        function createObject(name) {
            var obj = new Object();   //1.创建对象
            obj.name = name;           //2.添加属性                        
            obj.skill = function () {     //3.添加方法
                console.log('敲代码');
        }
        return obj;                  //4.返回创建好的对像 
        }
    
    
        //构造函数创建对象:(缺点:浪费内存)
        //函数名首字母大写(类名),使用this添加属性和方法,调用的时候前面必须加new
        function Student(name,sex,age) {
            this.name = name;
            this.study = function () {
                console.log("good");
            }
            //在构造函数中不用this,用普通的函数创建和变量创建是私有的,在外部无法直接访问
            //私有成员【需要更高的安全性】
            var lan="";
            function intro(){}
        }
        var stu = new Student(属性序列);
        stu.属性
        stu.函数();
    
    
原型(prototype)
  • 含义:每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。

  • 语法:

        //创建一个Student构造函数
        function Student() {}
        //1.通过原型添加属性和方法(共享)
        Student.prototype.name = "小红";
        Student.prototype.study = function () {
            console.log("good good study,day day up!!!!");
        }
    
    

    构造函数名.prototype 和 实例对象.proto 是完全相等的

        function Student(){};
        var oldW = new Student();
        oldW.__proto__ === Student.prototype // true
    
    

    原型属性与函数的使用

        Phone.prototype={
            call(){},
            message(){},
            internet(){}
        }
       //获取原型上面的属性和方法时,不需要加 __proto__,直接写名字即可
       var p = new Phone('iPhone12','gysz12b110@xx','white')
       p.call();
       //当我们想修改原型上的内容时,才需要通过__proto__
       p.__proto__.call=function(){}
    
    
Object.create()
    //创建一个没有原型的纯粹的对象
    var obj = Object.create(null);
    //创建一个带有原型【{run:function(){}}】的对象
    var obj2 = Object.create({run:function(){}})

  • 构造函数方式和原型方式对比

    prototype原型的好处:

    1. 给构造函数上挂载一个原型prototype,目的是为了减少某些函数去重复创建
    2. 原型上的内容创建一次就行,以后不论创建出来多少个对象,大家都共用
    3. 但是构造函数里面的内容,每new一次,就要创建一次,造成性能浪费。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3n7o8I6V-1634128183214)(images/20210909162829-16311862689372.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VPE0PYgh-1634128183215)(images/20210909162842-16311862822904.png)]

补充:
01 - 工厂模式
        //工厂函数(在函数内部创建对象,且return出来给外部使用)
        //好处:外部无需关注工厂函数里面具体是怎么实现的【隐藏细节】
        function factory(name,age){
            var obj = new Object();
            obj.myName=name;
            obj.myAge=age;
            return obj;
        }
        console.log(factory("frank",20))
        console.log(factory("rose",10))

02 - 构造函数
        //构造函数->类
        function Animal(type,name,age,sex){
            this.myType=type;
            this.myName=name;
            this.myAge=age;
            this.mySex=sex;
            var mySize="2米";
            //私有的方法,虽然写在Animal里面,但是它是属于window的,本质上和Animal没有关系
            function introduce(){
                console.log("我身长"+mySize);
            }
            this.eat=function(food){
                console.log(this.myName+"吃"+food)
            }
            this.sleep=function(){
                introduce();
                console.log("睡觉")
            }
        }
        //创建一个Animal类的实例
        var tiger = new Animal("爬行","壁虎",1,"母")
        //在构造函数中只要是用this点出来的属性和方法都是 public的【公开】
        tiger.eat("蚊子");
        // tiger.sleep=function(){
        //     console.log("我不睡觉")
        // }
            
        //在外部又创建了一个公开的属性,也叫mySize
        tiger.mySize="3米";
        console.log(tiger.mySize)

        tiger.sleep();
        //如何设计一些私有的private的属性和方法呢?
        //在构造函数中不要用this,就用普通的函数创建和变量创建就是私有的了

        //手机
        //品牌:brand
        //型号:type
        //屏幕:4.7
        //打电话、发短信、拍照、上网、GPS

03 - Prototype
        //1.每个对象都有__proto__属性
        function Person(name){
            this.name=name;
        }
        var p = new Person("frank");
        var arr = new Array();
        console.log(arr.__proto__);
        console.log(p)
        console.log(p.__proto__);

04 - Prototype
        function Student(name){
            this.name=name;
        }

        //prototype原型的好处:
        //给构造函数上挂载一个原型prototype,目的是为了减少某些函数去重复创建
        //原型上的内容创建一次就行
        //以后不论创建出来多少个对象,大家都共用

        //prototype的作用:函数与属性共享的
        Student.prototype.study=function(){
            console.log("学习")
            //这个方法是共享函数(所有Student的实例共享)
        }

        //构造函数名.prototype
        Student.prototype.school="蜗牛学院"

        var smallW = new Student("小王");
        var oldW = new Student("老王")

        oldW.study();
        //实例对象.__proto__
        oldW.__proto__.school='家里蹲'

        console.log(smallW)
        console.log(oldW)

        //构造函数名.prototype 和 实例对象.__proto__ 是完全相等的
        console.log(oldW.__proto__ === Student.prototype);

05 - Prototype
        function Student(name) {
            this.name = name;
        }
        //给Student设置一个原型,就是{},{}的原型是Object
        Student.prototype = {
            study:function(){},
            love:function(){}
        }
        console.log(new Student("X子文"))

        //对象默认的原型是 Object,Object是根
        console.log({name:'rose'});
        //创建一个没有原型的纯粹的对象
        var obj = Object.create(null);
        console.log(obj);
        //创建一个带有原型【{run:function(){}}】的对象
        var obj2 = Object.create({run:function(){}})
        console.log(obj2);

05 - Prototype
        //手机
        //品牌:brand
        //型号:type
        //屏幕:4.7
        function Phone(type,iCloud,color){
            this.type=type;
            this.iCloud=iCloud;
            this.color=color;
        }
        Phone.prototype={
            call(){
                console.log(this.type)
            },
            message(){},
            internet(){}
        }
        //打电话、发短信、拍照、上网、GPS
        var p = new Phone('iPhone12','gysz12b110@xx','white')
        //获取原型上面的属性和方法时,不需要加 __proto__,直接写名字即可
        p.call();
        //当我们想修改原型上的内容时,才需要通过__proto__
        p.__proto__.call=function(){
            console.log("重置。。。。")
        }

day05 - 面向对象(二)

01 - 作业鉴赏
        //程序员,老师,学生
        function Coder(name,age){
            this.name=name;
            this.age=age;
        }
        Coder.prototype.code=function(){
            console.log("coding.....")
        }
        
        function Teacher(name,age,subject){
            this.name=name;
            this.age=age;
            this.subject=subject;
            this.tech=function(){
                console.log("授课")
            }
        }
        Teacher.prototype = new Coder();

        function Student(name,age,major,sex,tel){
            this.name=name;
            this.age=age;
            this.major=major;
            this.sex=sex;
            this.tel=tel;
            this.study=function(){
                console.log("学习")
            }
        }
        Student.prototype=new Coder();

        var s = new Student("小王",20,'Web','男',1110);
        console.log(s);
        s.study();
        s.code();

02 - prototype优先
  • 原型模式的执行流程: (就近原则)

    1. 先查找构造函数实例里的属性或方法,如果有,立刻返回;
    2. 如果构造函数实例里没有,则去它的原型对象里找,如果有就返回
        function Fn() {
            this.a = '这是私有属性a';
            this.b = function() { alert('这是私有方法b'); }
        }
        Fn.prototype.a = '这是公共属性a';
        Fn.prototype.b = function() { alert('这是公共方法b'); }
        var f = new Fn();    
        alert(f.a);    f.b();
    
    
03 - hasOwnProperty
  • 如何判断属性是在构造函数的实例里,还是在原型里

    1. box.hasOwnProperty(‘name’)
    2. 实例里有返回 true,否则返回 false
    <ul>
            <li>111</li>
            <li>22</li>
            <li>33</li>
            <li>44</li>
        </ul>
        <script>
            var obj = {
                name:'jack',
                age:30
            }
            var arr = ["A","B","C",'D']
            for(var i in obj){
                console.log(i,obj[i],obj.hasOwnProperty(i))
            }
            for(let i in arr){
                console.log(i,arr[i])
            }
    
            var liList = document.getElementsByTagName("li");
            console.log(liList)
            for(let i in liList){
                console.log(i,liList.hasOwnProperty(i));
            }
    
            function Person(name,age){
                this.name=name;
                this.age=age;
            }
            Person.prototype.sex="女"
    
            var p = new Person("rose",20);
    
            console.log(p.hasOwnProperty("name"))//true表示name是Person构造函数里定义的
            console.log(p.hasOwnProperty("age"))//true表示age是Person构造函数里定义的
            console.log(p.hasOwnProperty("sex"))//false表示sex是原型上面定义的
        </script>
    
    
04 - constructor
  • 在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)

    		Person.prototype.constructor === Person //true
    
            function Person(){}
            // Person.prototype.name="jack"
            Person.prototype = {
                constructor:Person,
                name:"Nicholas",
                age:29,
                job:"Software Engineer",
                sayName:function(){}
            }
            var p1 = new Person();
            var p2 = new Person();
            console.log(p1)
            console.log(p1.constructor);//对象.constructor 【对象所在的类(构造函数)】
            console.log(Person.prototype.constructor);//构造函数名.prototype.constructor 【构造函数】
    
    
附加;prototype与constructor的关系、

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBGfJiIW-1634128183216)(images/20210910110205-16314192388592.png)]

05 - 原型链继承
  • 含义:原型与原型之间进行继承,形成了一个链条,称为原型链

  • 语法:子元素.prototype = 父元素实例

        Student.prototype = new Person();
        SmallStudent.prototype = new Student();
    
            //类:人、学生、小学生、一年级学生、一年级一班学生
            function Person(){
                this.name="人"
            }
            function Student(school){
                this.school=school
            }
            function SmallStudent(name,age,school){
                this.age = age;
            }
            //原型与原型之间进行继承,形成了一个链条,称为原型链
            Student.prototype = new Person();
            
            SmallStudent.prototype = new Student("学生--");
    
            //给原型上添加constructor,形成双向链条
            Student.prototype.constructor = Student;
            SmallStudent.prototype.constructor = SmallStudent;
    
    
    
            var s = new SmallStudent("小明",2,"蜗牛")
            console.log(s);
            console.log(s.role);
            console.log(s.name);
    
    
06 - 对象冒充继承
  • 对象冒充的原理:调用父类函数时改变this指向,定义子类的属性和方法

  • 在子类型中:父类型.call(this,参数1,参数2…);

  • 可以解决传参的问题,但是不能继承父类型原型中的属性和方法

        function Person(name){
            this.name=name;
        }
        function Student(name,school){
            Person.call(this,name)
            this.school=school
        }
        function SmallStudent(name,age,school){
            //创建子类之前,先调用父类,将父类里的this改成SmallStudent,给SmallStudent添加学校
            Student.call(this,name,school);
            this.age = age;
        }
        //好处:1.提取了多个类的共性做成一个父类,把共性的属性和方法都放父类里面
        //2.子类里面只设计属于自己的属性
        function HighStudent(name,height,school){
            Student.call(this,name,school);
            this.height=height;
        }
        var s = new SmallStudent("小明",3,"蜗牛")
        var h = new HighStudent("小红",180,'蜗牛')
        console.log(s.school,s.name,s.age)
        console.log(h.school,h.name,h.height)
    
    
07 - 混合继承
  • 混合继承 对象冒充+原型链继承

  • 对象冒充:继承父类型构造函数中的属性和方法

  • 原型链继承:继承父类型原型对象中的属性和方法

            //混合继承:
            //对象冒充:构造函数的动态参数
            //原型链:把父类的方法放进原型中
    
    	function Person(name,age){
            this.name=name;
            this.age=age;
            this.eat=function(){
                console.log("Person.吃饭")
            }
        }
        function Student(name,age,_class){
            Person.call(this,name,age);
            this._class=_class;
        }
        Student.prototype = new Person;
        Student.prototype.constructor = Student;
        function SmallStudent(name,age,_class){
            Student.call(this,name,age,_class)
            this.play=function(){
                console.log("玩耍")
            }
        }
        SmallStudent.prototype = new Student;
        SmallStudent.prototype.constructor = SmallStudent;
        var stu = new Student("班长大人",40,"3班");
        console.log(stu);
        stu.eat();
        var stu2 = new SmallStudent("小明",10,"3班");
        stu2.eat();
        stu2.play();
        console.log(stu2)
    
    
08 - ES6中的类
  • 动物类案例:

        class Animal{
            //通过new运算符在创建对象时才会调用的构造函数
            constructor(name,age){
                this.name=name;
                this.age=age;
            }
            hunter(){
                console.log(捕猎);
            }
            //get和set访问器中,访问属性时要加下划线,防止出现无限递归问题
            get name(){
                return this._name;
            }
            set name(value){
                this._name=value;
            }
        }
        new Animal("x",2).name;//当获取name值的时候,实际上是调用了 get name()
        new Animal("x",2).name="j"//当给name赋值的时候,实际上调用了set name()
    
    
  • 案例:

            //语法糖
            class Phone{
                constructor(brand,price,contact){
                    this.brand=brand;
                    this.price=price;
                    this.contact=contact;
                }
    
                //属性访问器:set、get
                set contact(newContact){
                    console.log("set contact",newContact)
                    if(newContact.length>0){
                        this._contact = newContact;
                    }
                }
    
                get contact(){
                    this._contact = this._contact.map(item=>{
                        //substr(从哪里开始截取,截取几个) substring(从哪开始截取,截取的结束位置-1)
                        return "**" + item.tel.substring(2)
                    })
                    return this._contact;
                }
            }
            
            var p = new Phone("MI",2999,[{name:"小明",tel:"12312"},{name:"小红",tel:"678"}]);
            p.contact=[];
            console.log(p.contact);
            p.contact=[{name:"小王",tel:"998282"},{name:"小绿",tel:"736338"}];
            console.log(p.contact);
    
    
10 - ES6中的继承
        //手机(父类)
        class Phone{
            constructor(brand,price,contact){
                this.brand=brand;
                this.price=price;
                this.contact=contact;
            }
        }

        //智能手机(子类)
        class SmartPhone extends Phone{
            constructor(brand,price,contact,OS){
                //调用父类构造函数
                super(brand,price,contact)
                this.OS = OS;
            }
        }
        
        var p = new SmartPhone("MI",2999,[{name:"小明",tel:"12312"},{name:"小红",tel:"678"}],'Android');
        console.log(p);

day06 - HTTP协议

HTTP协议
  • 什么是协议?
    • 用于计算机网络中数据传输的一个规则和标准
  • TCP/IP 协议 4 层结构
    • 链路层->网络层->传输层->应用层
  • 当你输入URL地址之后发生了什么?※
    1. 地址跳转
    2. 查找缓存
    3. 域名解析(DNS)解析成IP地址
    4. 建立TCP链接【包含三次握手】
    5. 发起请求(request)
    6. 接收响应(response)
    7. 四次挥手,断开连接
    8. 加载DOM树
    9. 加载CSS树
    10. DOM结构和CSS合并渲染
  • TCP协议
    • 特点:提供一种面向连接的、可靠的字节流服务
  • TCP协议三次握手※
image-20210913122020100
  • TCP协议四次挥手※
image-20210913122031201
  • HTTP协议(超文本传输协议)
    • 特点:※
      1. 简单快速、可以传输任意类型
      2. 无连接
      3. 无状态
  • 请求过程:※
    1. 建立连接
    2. 发送请求(request)
    3. 接收响应结果(response)
    4. 关闭连接
  • HTTP协议常用的几种请求方式※
    1. GET:明文传输,不安全,传输的数据量小【加载资源文件,查询数据】
    2. POST:以文件形式传输,传输的数据不限制【新增功能】
    3. HEAD:头部信息【配置信息】
    4. PUT:【修改功能】
    5. DELETE:【删除功能】
    6. OPTIONS:查看服务器支持的请求类型是什么
  • HTTP请求头格式 [HEAD]※
    1. 请求行:【传输类型 URL地址 HTTP版本号】
    2. 请求头:【key:value】
    3. 空行
    4. 请求正文:【参数】
  • HTTP响应头格式 [HEAD]※
    1. 响应行:【HTTP版本号 状态码】
    2. 响应头:【key:value】
    3. 空行
    4. 响应正文:【结果】
状态码与缓存
  • HTTP状态码【服务器给客户端的】※

    1xx:请求中
    2xx:成功范畴
    3xx:重定向
    4xx:客户端出错
    5xx:服务端报错

    100:请求
    200:OK
    301:永久重定向
    302:临时重定向
    304:当前资源来自于缓存
    400:客户端语法错误
    401 :客户端没权限
    403:服务的拒绝客户端的请求
    404:资源没找到
    500:服务的代码报错
    503:服务端繁忙

  • 关于HTTP的缓存※

    • 流程:

      1. 读取本地缓存->200
      2. 强制缓存【Expires,Cache-Control】->200
      3. 协商缓存【ETag,Last-Modified】-> 304
      4. 读取最新数据->200

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a75Bc2Ie-1634128183217)(images/Snipaste_2021-09-14_09-42-33.png)]

  • HTTP的端口号

    http协议默认端口号:80端口
    https协议默认端口号:443端口
    http端口号范围:1-65536之间,1-1024被系统占用
    推荐端口号:8080,8081,8082,8083

HTTPS
  • 传输方式:
    数据内容首先以对称加密方式(公钥)加密,传输过程再由非对称加密方式(私钥)加密的双重加密方式

  • 对称加密:

    发送方和接收方都用的同一个密钥 加密解密都是同一个密钥 从始至终只需要保存一个密钥就行

  • 非对称加密:

    发送方和接收方使用一对密钥,即公钥和私钥。一般私钥是保密不能被泄露的,公钥可以对外传播。

了解WebSocket
  • 基于TCP连接的一个长连接协议
    通常:
    1. 聊天室
    2. 股票
    3. 网络游戏
    4. 系统通知
补充:
01 - Super
  • super关键字

    1. super关键词指向当前对象的原型对象

    2. super()指代父类的构造方法

    3. super.函数名()可以调用父类函数

      案例:

      class Student extends Person{
          constructor(name,age,major){
              //调用父类的构造函数,并传参,且一定要写在第一行
              super(name,age);
              this.major=major;
          }
          //子类重写(覆盖)了父类函数:父类函数内容太广泛太笼统,不具体,并不能完成体现子类的特点
          work(){
              //用super.xxx 可以获取父类的成员
              super.work();
              console.log("学生的工作就是学习")
          }
      }
      
      
02 - Static
  • static关键字

    被static修饰的方法与属性:

    1. 不需要new对象,它在class创建的时候就一并产生

    2. 在创建class的时候它也就随之创建一次

    3. 用类名调用,而不是对象调用

              class Person{
                  constructor(name,age){
                      this.name=name;
                      this.age=age;
                  }
              }
      
              class Student extends Person{
                  constructor(name,age,major){
                      super(name,age);
                      this.major=major;
                  }
                  static role='kid'
                  static getMyName(){
                      console.log('getMyName : ' + this.name);//返回当前类名:Student
                  }
              }
              var s = new Student("jack",30,'Web');
              //1.被static修饰的成员,通过类名调用的,不是对象调用
              Student.getMyName();
              //2.被static修饰的成员归属于类的,不归属于对象
              //3.被static修饰的成员是该类创建时也一起创建的
      
              //平时用过的静态成员(大多是工具函数)
              console.log(Date.now());
              console.log(Math.PI);
      
      
03 - 私有属性
  • ES6中定义私有成员

    • 私有成员:在名称前面加 # ,访问范围仅限于class大括号以内
  • 私有属性

    • 必须先在constructor之前定义一下;普通属性不用预先定义

      class Animal{
          a;
          #b;
          constructor(a,b){
              this.a=a;
              this.#b=b;
          }
          run(){
              console.log("this.#b : " + this.#b)
          }
          #stop(){
              console.log("stop")
          }
      }
      
      
04 - TryCatch
  • 异常处理/异常捕获

            //语法错误
            // war s = "123";
    
            //逻辑错误:调试找到错误
    
            //难以预料:try(试试)-catch(捕获)
            try {
                //1.将有可能出错的代码放在try里面
                console.log('试一试')
                alertn(123);
            } catch (error) {
                //2.如果真的出错了,就会进入catch里面
                console.log('出错啦 :',error)
            }
            //3.用了try-catch之后,即使报错也不会影响后续的代码执行
            console.log("执行完毕")
    
    
        //主动抛出异常(主动报错)
        function play(){
            throw "当前函数不可用"
        }
    
    

day07 - 异步编程(一)

同步与异步※
  • 同步:阻塞式的,一定要等前一段代码结果出来之后才能继续执行后面的
  • 异步:非阻塞式,什么时候执行完了,会通过事件触发来告诉我们(事件是其中一种方式)
  • FileReader、setTimeout、setInterval
【阿贾克斯】
  • 含义:指一种创建交互式网页应用的网页开发技术

  • 作用:可以在不重新加载整个网页的情况下,对网页的某部分进行更新
    代码:

        /**
         * url 访问地址
         * method 请求方式:GET、POST
         * data 传递给后端的数据(POST才用)
         * callback 回调函数(将异步的结果放进去)
         */
        function ajax(url,method,data,callback){
            //1.创建XMLHttpRequest对象:xhr
            let xhr = new XMLHttpRequest();
            //2.打开通道
            xhr.open(method,url);
            if(method.toUpperCase()=='POST'){
                xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            }
            //3.发送请求
            xhr.send(data);
            //4.通过事件来获取响应结果
            xhr.onreadystatechange=function(){
                //5.readyState=4说明整个请求已经完成了
                if(this.readyState==4){
                    //6.获取HTTP状态码,如果是200则成功
                    if(this.status==200){
                        let res = JSON.parse(this.response)
                        if(res.errcode){
                            alert(res.errmsg)
                            return;
                        }
                        //将结果传给回调函数
                        callback(res);
                    }else{
                        //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found
                        console.log(this.statusText)
                    }
                }
            }
        }
    
    
Content-Type:
  1. 纯文本 text/plain
  2. JSON application/json
  3. form表单 application/x-www-form-urlencoded
  4. 文件上传 multiple-form
回调地狱
  • 多层回调函数嵌套,使得程序变得难以维护,可读性差

        setTimeout(function() {
            console.log('Yay!');
            setTimeout(function() {
                console.log('Yahoo!');
                    setTimeout(function(){
                    //回调地狱
                },1000)
            }, 1000)
        }, 1000);
    
    
Promise(承诺)
  • ES6推出了Promise语法结构来解决回调地狱问题。

  • 这也就表达了将来会执行的操作,代表异步操作。

  • 三种状态:

    pending(进行中)、fulfilled(已成功)和rejected(已失败)

  • 状态改变的过程:

    pending->fulfilled
    pending->rejected
    一旦变成了成功或失败状态,状态就不会再变化。

  • 创建Promise实例:

        const promise = new Promise((resolve, reject) => {
            // do something here ...
            if (success) {
                resolve(value); // fulfilled
            } else {
                reject(error); // rejected
            }
        });
        //通过then方法,分别指定resolved状态和rejected状态的回调函数
        promise.then(function(value) {
            // success
        }, function(error) {
            // failure
        });
    
    
  • 用Promise改造Ajax:

        /**
         * url 访问地址
         * method 请求方式:GET、POST
         * data 传递给后端的数据(POST才用)
         */
        function ajax(url,method,data){
            return new Promise((resolve,reject)=>{
                //1.创建XMLHttpRequest对象:xhr
                let xhr = new XMLHttpRequest();
                //2.打开通道
                xhr.open(method,url);
                if(method.toUpperCase()=='POST'){
                    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
                }
                //3.发送请求
                xhr.send(data);
                //4.通过事件来获取响应结果
                xhr.onreadystatechange=function(){
                    //5.readyState=4说明整个请求已经完成了
                    if(this.readyState==4){
                        //6.获取HTTP状态码,如果是200则成功
                        if(this.status==200){
                            let res = JSON.parse(this.response)
                            if(res.errcode){
                                alert(res.errmsg)
                                return;
                            }
                            //将结果传给回调函数
                            resolve(res);
                        }else{
                            //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found
                            reject(this.statusText)
                        }
                    }
                }
            })
        }
        let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list'
        ajax(url,"GET",null).then(result=>{
            if(result instanceof Array){
                //遍历结果
                result.forEach(item=>{
                    //创建LI标签
                    let li = document.createElement("li");
                    li.innerHTML = item.name +":"+ item.sex;
                    //将LI追加到UL中
                    document.getElementById("parent").appendChild(li);
                })
            }
        },error=>{
            console.log("失败:" +error);
        })
    
    
Promise中的异常捕获:
  • 方式一:

    ajax(‘GET’,’api/seller.do’,’username=jackie’).then((data)=>{ console.log(data);//成功获得结果 },(err)=>{ console.log(err);//获取错误信息 }

  • 方式二:

    ajax(‘GET’,’api/seller.do’,’username=jackie’).then((data)=>{ console.log(data);//成功获得结果 }).catch(err=>{ console.log(err);//获取错误信息 })

补充:
01 - 作业
02 - 原生Ajax
        /**
         * url 访问地址
         * method 请求方式:GET、POST
         * data 传递给后端的数据(POST才用)
         * callback 回调函数(将异步的结果放进去)
         */
        function ajax(url,method,data,callback){
            //1.创建XMLHttpRequest对象:xhr
            let xhr = new XMLHttpRequest();
            //2.打开通道
            xhr.open(method,url);
            if(method.toUpperCase()=='POST'){
                xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            }
            //3.发送请求
            xhr.send(data);
            //4.通过事件来获取响应结果
            xhr.onreadystatechange=function(){
                //5.readyState=4说明整个请求已经完成了
                if(this.readyState==4){
                    //6.获取HTTP状态码,如果是200则成功
                    if(this.status==200){
                        let res = JSON.parse(this.response)
                        if(res.errcode){
                            alert(res.errmsg)
                            return;
                        }
                        //将结果传给回调函数
                        callback(res);
                    }else{
                        //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found
                        console.log(this.statusText)
                    }
                }
            }
        }
        // let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list'
        // ajax(url,"GET",null,function(result){
        //     if(result instanceof Array){
        //         //遍历结果
        //         result.forEach(item=>{
        //             //创建LI标签
        //             let li = document.createElement("li");
        //             li.innerHTML = item.name +":"+ item.sex;
        //             //将LI追加到UL中
        //             document.getElementById("parent").appendChild(li);
        //         })
        //     }
        // });
        let url = 'http://yapi.smart-xwork.cn/mock/91220/user/add';
        //Content-Type:
        //纯文本 text/plain
        //JSON application/json
        //form表单    application/x-www-form-urlencoded
        //文件上传     multiple-form
        let params = new URLSearchParams();
        params.append("name","Jerry")
        params.append("age","2")
        params.append("sex","男")
        params.append("phone","110120119114")
        
        ajax(url,"POST",params,function(res){
            console.log(res);
        })

        ajax('./data.json',"GET",null,function(res){
            console.log(res);
        })

03 - Promise
        var promise = new Promise(function(resolve,reject){
            //ajax请求
            console.log('1.发起ajax请求');
            var random = Math.random();
            console.log("2.产生随机数:" +random)
            if(random>0.5){
                //走成功那条路
                resolve("success")
            }else{
                //走失败那条路
                reject("fail")
            }
        })

        promise.then(function(res){
            //成功的处理
            console.log(res);
        },function(err){
            console.log(err);
            //失败的处理
        })

04 - Promise
        //要求等待1秒后弹出”Yay”,然后再等1秒弹出”Yahoo”,再等1秒弹出“God”
        new Promise((resolve,reject)=>{
            setTimeout(function(){
                console.log("Yay")
                resolve("Yahoo")
            },1000)
        }).then(function(res){
            setTimeout(function(){
                console.log(res)
            },1000)
        }).then(function(){
            setTimeout(function(){
                console.log("God")
            },1000)
        })

05 - Promise
        //要求等待1秒后弹出”Yay”,然后再等1秒弹出”Yahoo”,再等1秒弹出“God”
        function p(str){
            return new Promise(resolve=>{
                setTimeout(function(){
                    resolve(str)
                },1000)
            })
        }
        var promise = p("Yay")

        var promise2= promise.then(function(res){
            console.log(res);
            return p("Yahoo") //再次调用p方法,实际上是重新new了一个Promise对象,赋值给promise2
        })
        
        var promise3= promise2.then(function(res){
            console.log(res);
            return p("God") //再次调用p方法,实际上是重新new了一个Promise对象,赋值给promise3
        })
        
        promise3.then(res=>{
            console.log(res);
        })

06 - Promise_Ajax
        /**
         * url 访问地址
         * method 请求方式:GET、POST
         * data 传递给后端的数据(POST才用)
         */
        function ajax(url,method,data){
            return new Promise((resolve,reject)=>{
                //1.创建XMLHttpRequest对象:xhr
                let xhr = new XMLHttpRequest();
                //2.打开通道
                xhr.open(method,url);
                if(method.toUpperCase()=='POST'){
                    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
                }
                //3.发送请求
                xhr.send(data);
                //4.通过事件来获取响应结果
                xhr.onreadystatechange=function(){
                    //5.readyState=4说明整个请求已经完成了
                    if(this.readyState==4){
                        //6.获取HTTP状态码,如果是200则成功
                        if(this.status==200){
                            let res = JSON.parse(this.response)
                            if(res.errcode){
                                alert(res.errmsg)
                                return;
                            }
                            //将结果传给回调函数
                            resolve(res);
                        }else{
                            //7.如果状态码不是200,我们就打印状态文本,例如:404 文本就是 Not Found
                            reject(this.statusText)
                        }
                    }
                }
            })
        }
        let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list'
        ajax(url,"GET",null).then(result=>{
            if(result instanceof Array){
                //遍历结果
                result.forEach(item=>{
                    //创建LI标签
                    let li = document.createElement("li");
                    li.innerHTML = item.name +":"+ item.sex;
                    //将LI追加到UL中
                    document.getElementById("parent").appendChild(li);
                })
            }
        },error=>{
            console.log("失败:" +error);
        })

07 - 回调函数
        //传统做法:回调函数来得到异步结果
        function a(num,str,bol,callback){
            callback();
        }
        a(12,"hello",true,function(){
            console.log("66666666")
        });

        //Promise的出现就是为了干掉回调函数这种传统写法
        function a(num,str,bol){
            return new Promise(resolve=>{
                resolve("66666666")
            })
        }
        a().then(res=>{
            console.log(res)
        })

08 - 错误捕获
        var promise = new Promise(function(resolve,reject){
            //ajax请求
            console.log('1.发起ajax请求');
            var random = Math.random();
            console.log("2.产生随机数:" +random)
            if(random>0.5){
                //走成功那条路
                resolve("success")
            }else{
                //走失败那条路
                reject("fail")
            }
        })

        // promise.then(成功的回调,失败的回调)
        // promise.then(function(res){
        //     //成功的处理
        //     console.log(res);
        // },function(err){
        //     console.log(err);
        //     //失败的处理
        // })

        //promise.then(成功回调).catch(失败的回调)
        promise.then(res=>{
            console.log(res)
        }).catch(err=>{
            console.log(err);
        })

day08 - 异步编程(二)

Promise.all
  • Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

        var p1 = new Promise(function (resolve,reject) {});
        var p2 = new Promise(function (resolve,reject) {});
        var p3 = new Promise(function (resolve,reject) {});
        var p = Promise.all([p1,p2,p3]);
    
    
  • p的状态,由p1,p2,p3决定,全部实例对象为resolve,p的状态才会resolve,所有对象的返回值组成一个数组,传递给p的回调函数。任何一个对象为rejected,p的状态就变成rejected

Promise.allSettled
  • 同时启动多个Promise实例,返回多个结果[允许有的成功,有的失败]

        Promise.allSettled([
            Promise.resolve('a'),//创建了一个成功状态的Promise对象
            Promise.reject('b'),//创建一个失败状态的Promise对象
        ]).then(arr => console.log(arr))
    
    
Promise.race[比赛]
    //只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
    //那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
    var p =Promise.race([p2(),p1(),p3()]);
    p.then(res=>{
        console.log(res)
    })

async与await[能让我们的异步代码看起来像是同步代码]
  • async:作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行。

        async function timeout() {
            return 'hello world';
        }
        console.log(timeout()); //返回一个Promise对象
        console.log('虽然在后面,但是我先执行');
        timeout().then(result => {
            console.log(result);  // 用这个对象.then才能获取结果 hello world
        })
    
    
  • await:等待的意思,它后面跟着一个返回promise 对象的表达式,注意await 关键字只能放到async 函数里面。

        async function show(){
            return 123;
        }
        async function play(){
            var res =await show();
            console.log(res); //123
        }
        play();
    
    
补充:
01 - Promise.all
        function p1(){
            return new Promise(resolve=>{
                resolve("success")
            })
        }
        function p2(){
            return new Promise((resolve,reject)=>{
                reject("fail")
            })
        }
        function p3(){
            return new Promise(resolve=>{
                resolve("success")
            })
        }
        function start(){
            //如果三者都返回成功,最终结果就是成功;如果三者有一个返回失败,最终结果就是失败
            Promise.all([p1(),p2(),p3()]).then(res=>{
                console.log(res);
            }).catch(err=>{
                console.log(err)
            })
        }
        start();

02 - Promise.allSettled
        //Promise的三种状态
        //还没出结果的时候:pending
        //成功结果:fulfilled
        //失败结果:rejected
        //pending->fulfilled  或 pending->rejected  (只能是从没结果到成功,或失败)
        //fulfilled->rejected  (不会出现从成功变成失败,或从失败变成成功)

        //同时启动多个Promise实例,返回多个结果[允许有的成功,有的失败]
        function start(){
            Promise.allSettled([
                Promise.resolve("111"), //创建了一个成功状态的Promise实例
                Promise.reject("222"),//创建了一个失败状态的Promise实例
                Promise.resolve("333"), //创建了一个成功状态的Promise实例
            ]).then(res=>{
                console.log(res);
            })
        }
        start();

03 - Promise.race
        function p1(){
            return new Promise(resolve=>{
                resolve("success1")
            })
        }
        function p2(){
            return new Promise((resolve,reject)=>{
                reject("fail")
            })
        }
        function p3(){
            return new Promise(resolve=>{
                resolve("success2")
            })
        }
        function start(){
            //race:比赛
            //只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
            //那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
            var p =Promise.race([p2(),p1(),p3()]);
            p.then(res=>{
                //最终结果就是执行最快的那个Promise,如果没有时间上的差异,就是按先后顺序
                console.log(res)
            })
        }
        start();

04 - async
        //给函数前面加async关键字,函数的返回值就会变成一个Promise对象
        //如果我们手动在函数里面return了一个值,则这个值就是Promise对象里面的value,通过then可以取出
        async function show(){
            return 123;
        }

        // 相当于写了下面的代码
        // function show(){
        //     return new Promise(resolve=>{
        //         resolve(123)
        //     })
        // }

        //也相当于下面的代码
        // function show() { 
        //     return Promise.resolve(123);
        //  }

        show().then(res=>{
            console.log(res);//123
        })

05 - async_await
        //async - await:能让我们的异步代码看起来像是同步代码
        async function show(){
            return 123;
        }
        //await关键字只能在被async修饰的function里面使用
        async function play(){
            //用await来代替 .then方法,res就是then()里面正确返回的结果
           try {
            var res =await show();
            console.log(res);
           } catch (error) {
            console.log("万一报错了,执行这里,原因:"+error)   
           }
        }
        play();

06 - async_ajax
        function ajax(url, method, data) {
            return new Promise((resolve,reject)=>{
                let xhr = new XMLHttpRequest();
                xhr.open(method, url);
                throw "错错错,是我的错"
                if (method.toUpperCase() == 'POST') {
                    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                }
                xhr.send(data);
                xhr.onreadystatechange = function () {
                    if (this.readyState == 4) {
                        if (this.status == 200) {
                            let res = JSON.parse(this.response)
                            if (res.errcode) {
                                alert(res.errmsg)
                                return;
                            }
                            resolve(res);
                        } else {
                            reject(this.statusText)
                        }
                    }
                }
            })
        }
    
        //使用async+await 让代码看起来像同步代码,代替了过去的回调函数,以及 then
        async function play(){
            try {
                let url = 'http://yapi.smart-xwork.cn/mock/91220/user/list'
                let res =await ajax(url,'GET',null)
                console.log(res);
            } catch (error) {
                console.log(error)
            }
        }
        
        play();

        console.log("黑色")
        console.error("红色")
        console.info("蓝色")
        console.warn("黄色")

day09 - WebPack常用配置

webpack.config.js
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const Terser =require('terser-webpack-plugin');
const Clean = require('clean-webpack-plugin');
const WebpackBar = require('webpackbar');
module.exports={
    //环境:development(开发环境)、production(线上环境)
    mode:'development',
    // 入口
    entry:{
        index:'./src/index.js',
        print:'./src/print.js',
        app:'./src/app.js'
    },
    // 出口
    output:{
        filename:'[name].bundle.js',
        path:path.resolve(__dirname,'dist')
    },
    //插件配置
    plugins:[
        new htmlWebpackPlugin({
            filename:'index.html',  //生成的html的文件名,默认就是index.html
            title:'Webpack4.x学习', //网页的标题
            favicon:'./favicon.ico',//网页小图标
            inject:'body',//将生成的js插入在body里面,也可以写head
            chunks:['index'],//只引入print那个js文件
            minify:{ //压缩规则
                'removeComments':true, //删除所有注释
                'collapseWhitespace':false,//删除所有的空格、换行
            }
        }),
        new htmlWebpackPlugin({
            filename:'login.html',  //生成的html的文件名,默认就是index.html
            title:'登录', //网页的标题
            template:'./src/login_template.html', //设置一个模板文件
            favicon:'./favicon.ico',//网页小图标
            inject:'body',//将生成的js插入在body里面,也可以写head
            chunks:['app'],//只引入app那个js文件
            minify:{ //压缩规则
                'removeComments':true, //删除所有注释
                'collapseWhitespace':false,//删除所有的空格、换行
            }
        }),
        new MiniCssExtractPlugin({filename:"[name].css"}),//分离CSS
        new OptimizeCssAssetsPlugin(),//压缩CSS文件
        new Terser(), //在开发环境下压缩JS文件
        new Clean.CleanWebpackPlugin(), //清理dist文件夹
        new WebpackBar() //打包进度条
    ],
    module:{
        rules:[
            {
                test:/\.css$/,
                // use:['style-loader','css-loader']
                use: [{loader:MiniCssExtractPlugin.loader},'css-loader']
            },
            {
                test:/\.(jpg|png|gif|webp)$/,
                use:[{
                    loader:'url-loader',
                    options:{
                        limit:8192,
                        outputPath:'images/'
                    }
                }]
            },
            {
                test:/\.(ttf|woff)$/,
                use:['file-loader']
            }
        ]
    }
}

补充:
01 - webpack配置相关
  • 使用参考:

    1. 安装node.js

    2. 安装淘宝镜像npm install -g cnpm -- registry=https://registry.npm.taobao.org

    3. 创建“工作区”文件夹

    4. cmd切换到该目录

    5. npm init -y该文件夹生成package.json文件

      webpack.config.js手动新建转换配置文件

    6. 安装cnpm install --save-dev webpack@4.32.2cnpm install --save-dev webpack-cli@3.3.11(我感觉叫webpack支持)

    7. 这是文件夹大致分布。(dist输出文件夹,src输入文件夹,父盒子 工作配置相关)image-20210917195718459

    8. index.html修改(略)

    9. package.json设置

      {
        "name": "day09",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "start": "webpack-dev-server --open --config webpack.dev.js",
          "build": "webpack --config webpack.prod.js"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "devDependencies": {
          "clean-webpack-plugin": "^4.0.0",
          "css-loader": "^5.0.2",
          "html-webpack-plugin": "^4.5.2",
          "mini-css-extract-plugin": "^0.8.2",
          "optimize-css-assets-webpack-plugin": "^6.0.1",
          "style-loader": "^2.0.0",
          "terser-webpack-plugin": "^1.4.5",
          "url-loader": "^4.1.1",
          "webpack": "^4.32.2",
          "webpack-bundle-analyzer": "^4.4.2",
          "webpack-cli": "^3.3.11",
          "webpack-dev-server": "^3.11.2",
          "webpack-merge": "^5.8.0",
          "webpackbar": "^5.0.0-3"
        }
      }
      
      

      webpack.config.js设置

      const path = require('path');
      
      // 引入jquery
      // const $ = require('jquery');
      
      // 新建html
      const htmlWebpackPlugin = require('html-webpack-plugin');
      // 把css抽出为单独的文件
      const MiniCssExtractPlugin = require("mini-css-extract-plugin");
      // 压缩css
      const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
      // 压缩js
      const Terser = require('terser-webpack-plugin');
      // 每次构建前清理 /dist 文件夹
      const Clean = require('clean-webpack-plugin');
      // 打包进度条
      const WebpackBar = require('webpackbar');
      // 分析并可视化构建后的打包文件
      const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
      
      
      
      // 导出webpack配置内容
      module.exports = {
          mode: 'development',
          // 入口
          // entry: './src/index.js',
          entry: {
              index: './src/index.js',
              // print:'./src/print.js',
              app: './src/app.js'
          },
          // 出口
          output: {
              // filename: 'bundle.js',
              filename: '[name].bundle.js',
              // __dirname:代表当前文件的绝对路径
              path: path.resolve(__dirname, 'dist')
          },
          plugins: [
              new htmlWebpackPlugin({
                  filename: 'index.html',  //生成的html的文件名,默认就是index.html
                  title: '张胖胖', //网页的标题
                  favicon: './favicon.ico',//网页小图标
                  inject: 'body',//将生成的js插入在body里面,也可以写head
                  chunks: ['index'],//只引入print那个js文件
                  minify: { //压缩规则
                      'removeComments': false, //删除所有注释
                      'collapseWhitespace': false,//删除所有的空格、换行
                  }
              }),
              new htmlWebpackPlugin({
                  filename: 'login.html',  //生成的html的文件名,默认就是index.html
                  title: '登录', //网页的标题
                  template: './src/index.html', //设置一个模板文件
                  favicon: './favicon.ico',//网页小图标
                  inject: 'body',//将生成的js插入在body里面,也可以写head
                  chunks: ['app', 'index'],//只引入app那个js文件
                  minify: { //压缩规则
                      'removeComments': false, //删除所有注释
                      'collapseWhitespace': false,//删除所有的空格、换行
                  }
              }),
              new MiniCssExtractPlugin({ filename: "[name].css" }),
              new Clean.CleanWebpackPlugin(),
              new WebpackBar({ color: 'pink' }),
              // new OptimizeCssAssetsPlugin(),
              // new Terser(),
              // new BundleAnalyzerPlugin,
      
      
          ],
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      // use: ['style-loader', 'css-loader']
                      use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader']
                  },
                  {
                      test: /\.(jpg|png|gif|webp)$/,
                      use: [{
                          loader: 'url-loader',
                          options: {
                              limit: 8192,
                              outputPath: 'images/'
                          }
                      }]
                  }
              ]
          },
          // 以服务器打开实时更新
          devServer: {
              port: 8000,
              host: '127.0.0.1',
              contentBase: './dist',
              overlay: {
                  errors: true
              },
          }
      }
      
      

      。(index.js随便输入个东西,此时基本就可以用npm run build运行看看了,具体见readme)

    10. 安装loader(插件)--save-dev忘了怎么说了:

      • 处理css:cnpm install --save-dev style-loader@2.0.0cnpm install --save-dev css-loader@5.0.2

        规则:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UnHyoHu-1634128183218)(images/image-20210917200556054.png)]

      • url:cnpm install --save-dev url-loader小于8kb的图片用什么64转换显示。

        规则:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DSeeczG-1634128183219)(images/image-20210917200626238.png)]

      • 打包进度条:cnpm install --save-dev webpackbar

        new一个!new WebpackBar({ color: 'pink' }),

      • 分析并可视化构建后的打包文件cnpm install --save-dev webpack-bundle-analyzer

        new一个!new BundleAnalyzerPlugin,

      • 以服务器打开:cnpm install --save-dev webpack-dev-server@3.11.2

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCqVzLWR-1634128183220)(images/image-20210917200927304.png)]

      • 拆分webpack.config.js插件:cnpm install --save-dev webpack-merge

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSyctkMS-1634128183220)(images/image-20210917201043750.png)]

      • 时间:cnpm install time-stamp

      • 全部重新安装:cnpm install

  1. 安装plugin(工具):

    • 创建html:cnpm install --save-dev html-webpack-plugin@4.5.2

      规则:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPm3HSEb-1634128183221)(images/image-20210917201335530.png)]

    • 把css抽离成单独的css文件:cnpm install mini-css-extract-plugin@0.8.2 -D

      new一个!

    • CSS代码压缩:cnpm install --save-dev optimize-css-assets-webpack-plugin

      new一个!

    • 在开发环境下,压缩JS代码:cnpm install --save-dev terser-webpack-plugin@1.4.5

      new一个!

    • 每次构建前清理 /dist 文件夹,是比较推荐的做法:cnpm install --save-dev clean-webpack-plugin

      new一个!new 名.CleanWebpackPlugin(),

02 - cmd相关
  • cmd常用命令
    1. node xx.js运行JS文件
    2. cls清屏
    3. dir列出当前目录下的所有文件
    4. cd 目录名进入指定的文件夹
    5. md 目录名创建一个文件夹
    6. rd 目录名删除该文件夹(只能删空文件夹)
    7. 盘符号:切换到指定盘符

day10 - GIT命令

集中式的版本控制系统:SVN,CVS
  • 版本库是集中存放在中央服务器的,而干活的时候,用的是自己的电脑,所以要先从中央服务器取得最新的版本,
    然后开始干活,干完活了,再把自己的活推送给中央服务器。
    中央服务器就好比是一个图书馆.你要改一本书.必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
    集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,

    可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟

分布式版本控制系统:Git
  • 分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,
    就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?
    比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,

    你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

分布式 VS 集中式
  • 集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,
    某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。
    而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
    由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。
    同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统。

    Git的优势不单是不必联网这么简单,后面我们还会看到Git极其强大的分支管理,把SVN等远远抛在了后面。

安装Git
  • Linux:
    终端中直接输入 sudo apt-get install git

  • Mac:
    运行Xcode,菜单“Xcode”->“Preferences”,
    在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了

  • Windows:
    下载地址:https://git-for-windows.github.io
    安装后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
    最后:
    在命令行输入名字和邮箱进行登记:
    $ git config —global user.name “Your Name”

    $ git config —global user.email “email@example.com

创建版本库(repository)
  • 可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,
    以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
    1. 创建一个空的文件夹(frankGit),确保目录名和父级目录名没有中文和符号
    2. 命令行:git init 把这个目录变成Git可以管理的仓库
      tips:
      所有的版本控制系统,其实只能跟踪文本文件的改动,也就是在文本中修改和添加内容都可以被检测到。
      图片、视频、Word这种二进制文件,无法跟踪变化,只能检测文件大小发生了变化。
将文件添加到版本库
  1. 创建一个readme.md文件
    内容:do you love me?
  2. 放在frankGit或frankGit的子目录
  3. 命令行: git add readme.md //把文件添加到仓库暂存区,可以添加多次之后再进行commit
  4. 命令行: git commit -m “本次提交了XXXX,么么哒” //把文件提交到仓库
查看版本库状态和修改记录
  1. 修改readme.md文件 内容:do you hate me?
  2. 命令行:git status //仓库当前的状态
  3. 查看修改具体内容:git diff
  4. 再次提交到版本库暂存区:git add readme.md
  5. 再查看状态:git status
  6. 再次提交到版本库:git commit -m “呵呵,这次我不爱你了。”
  7. 再查看状态:git status
    [每次修改,如果不add到暂存区,那就不会加入到commit中。]
版本回退
  1. 命令行:git log //查看提交的历史记录
  2. 命令行:git log —pretty=oneline //美化输出结果,可以看到一串十六进制的版本号
  3. 命令行:git reset —hard HEAD^ //回退到上一个版本
  4. 命令行:git reset —hard 版本号前几位 //也可以通过版本号跳转到指定版本
  5. 命令行:git reflog //查看命令的历史记录
撤销修改
  1. 命令行:git checkout — readme.md //撤销本地文件的修改
  2. 命令行:git reset HEAD readme.md //撤销暂存区文件的修改
  3. 命令行:git reset —hard HEAD^ //撤销版本库里文件的修改:回退到上一个版本
删除文件
  1. 命令行:rm readme.md //删除本地文件
  2. 命令行:git status //提示本地和版本库不一致
  3. 命令行:git rm readme.md //删除缓冲区文件
  4. 命令行:git commit -m “本次删除了readme文件,以此为据” //删除版本库里文件
  5. 命令行:git checkout — readme.md //如果是误删,可以撤销删除操作(本地)
配置远程仓库
  • GitHub:用于提供Git仓库托管服务 ,只要注册一个GitHub账号,就可以免费获取Git远程仓库
  • 步骤:
    1. 打开github,注册一个账号。
    2. 创建ssh key,在C:\用户\用户名.ssh目录,如果没有id_rsa文件和id_rsa.pub文件,就需要创建。
      2-1. ssh-keygen -t rsa -C “154580967@qq.com”
      2-2. 一路默认
    3. 登录GitHub,打开“Account settings”,“SSH Keys”页面:
      3-1. 点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
      3-2. 点“Add Key”,就应该看到已经添加的Key:
      [在GitHub上免费托管的Git仓库,任何人都可以看到。所以,不要把敏感信息放进去。]
从本地同步到远程库
  • 已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步
  • 步骤:
    1. 登录GitHub,在右上角找到“Create a new repo”按钮,创建一个新的仓库
    2. 在Repository name填入frankGit,其他默认,点击“Create repository”,就成功地创建了一个新的Git仓库
    3. 命令行:git remote add origin git@github.com:自己的帐户名/frankGit.git //origin是自定义远程库的名字
      [git 解决fatal: Not a git repository:git init]
    4. 命令行:git push -u origin master //将当前分支推送到远程,并将本地master和远程master关联起来
      [推送前确保本地仓库是有东西的,commit过的]
    5. 命令行:git push origin master //把本地master分支的最新修改推送至GitHub
从远程库克隆到本地
  1. 登录GitHub,创建一个新的仓库,名字叫gitskills
  2. 勾选Initialize this repository with a README,自动创建README.md文件。
  3. 命令行:git clone git@github.com:自己的帐户名/gitskills.git
    [可让多人从同一个仓库下载到自己的本地进行开发]
分支管理
  • 分支就是科幻电影里面的平行宇宙,如果两个平行宇宙互不干扰,那对现在的你也没啥影响。
    默认分支:master
  • 使用:
    1. 命令行:git branch dev //创建分支dev
    2. 命令行:git checkout dev //切换到dev分支
    3. 命令行:git checkout -b dev //创建分支dev,并切换到dev分支
    4. 命令行:git branch //查看当前分支,前面带*号的就是当前分支
    5. 命令行:git add readme.md
      git commit -m “本次是从dev分支提交的”
    6. 命令行:git checkout master //切换回master
    7. 命令行:vi readme.md //再查看文件,会发现文件中刚添加的内容不存在了。
    8. 命令行:git merge dev //合并指定分支到当前分支
    9. 命令行:git branch -d dev //删除dev分支
    10. 命令行:git branch //再查看,dev分支就没有了
    11. 如果两个分支同时修改一个文件,提交。再合并,就会出现冲突。
    12. 只需要将冲突的文件打开,删除标记,重新add和commit
    13. 命令行:git branch -d dev
    14. 命令行:git log --graph //查看分支合并图
强行删除分支(feature)
  1. 命令行:git checkout -b feature //创建新分支并切换
  2. 命令行:vi work.js //创建work.js文件
  3. 命令行:git add work.js //添加到缓存区
  4. 命令行:git commit -m “添加一个新的分支咯” //添加到版本库一个新分支
  5. 命令行:git checkout dev //切换回dev分支
  6. 命令行:git branch -d feature //还未合并就要马上删除feature分支
  7. 命令行:git branch -D feature //必须强行删除才可以
多人协作
  1. 命令行:git remote //查看远程库的信息
  2. 命令行:git remote -v //显示更详细的远程库信息
  3. 命令行:git push origin master //把master分支上的所有本地提交推送到远程库
  4. 命令行:git push origin dev //推送dev分支到远程库
    强制推送:git push -u origin dev -f
  5. 当自己和伙伴提交有冲突时,使用git pull把最新的提交从远程库下载下来,在本地合并,再推送。
    命令行:git branch --set-upstream dev origin/dev //指定本地dev分支与远程origin/dev分支的链接
    命令行:git pull --rebase origin master
  6. 命令行:git add readme.md
  7. 命令行:git commit -m “合并后再提交”
工作流程
  • [repository-点击settings-选择collaborators-搜索框中搜索合作者账号然后add,然后给合作者发确认邮件]
    [必须在SSH中添加合作者的pub.key]
    1. 克隆到本地环境
    2. 修改文件先在本地进行提交
    3. 用git push origin branch-name推送自己的修改;
    4. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull origin branch-name 试图合并;
    5. 如果合并有冲突,则解决冲突,并在本地提交;
    6. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
    7. 如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,
      用命令git branch --set-upstream branch-name origin/branch-name。
    8. git 出现 fatal: refusing to merge unrelated histories 错误,其实这个问题是因为 两个 根本不相干的 git 库
      git pull origin master --allow-unrelated-histories 把两段不相干的 分支进行强行合并
      [master:主分支要时刻与远程同步]
      [dev:开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步]
      [bug:本地修复bug记录,不需要推送到远程]
      [feature:取决于你是否和你的小伙伴合作在上面开发]
常用的Linux命令
  1. 命令:ls【列出当前目录里面所有的文件和文件夹】
  2. 命令:touch login.html【创建一个login.html空文件】
  3. 命令:cat login.html【在命令行中预览login.html文件的内容】
  4. 命令:clear 【清屏】
  5. 命令:mkdir 文件夹名 【创建一个文件夹】
  6. 命令:pwd【输出当前的路径】
  7. 命令:vim login.html【vim是系统内置的一款编辑器】
    1. 命令:vim login.html【用vim打开login.html文件】
    2. 按下:i【切换到编辑模式】
    3. 随意的修改文件内容
    4. 按下:ESC【关闭编辑模式】
    5. 按下:冒号 + wq【保存并退出vim】
补充:
01 - GIT常用的命令
  • git config --global user.name "自己的名字"

    git config --global user.email "自己的邮箱"

    git config user.name 查看当前用户名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZhyFW7vX-1634128183222)(images/git命令.jpg)]

day11 - Node模块(一)

Node的特点 ♥
  1. 本身采用JS语言编写,基于Chrome的V8引擎进行解析的。
  2. 无需安装运行服务器软件,就可以直接创建一个HTTP服务。
  3. 单线程
  4. 非阻塞IO
  5. 事件驱动
Node的模块化 ♥
  • 特点:基于CMD标准-同步的模块化标准
    语法:

        //文件A:导入
        const 模块名 = require('路径');
        模块名.成员1;
        模块名.成员2();
    
    
        //文件B:导出
        exports.成员1 =;
        exports.成员2 = function(){};
    
        //导出
        module.exports = {
            变量名,函数名
        }
    
    
ES6的模块化
    //文件A:导出
    class Animal{
        constructor(name){
            this.name=name;
        }
    }
    function print(){
        console.log("打印。。。。")
    }
    function play(){
        console.log("播放")
    }
    //具名导出
    export const show= () =>{
        console.log("show...")
    };
    //具名导出
    export {print,play};
    //默认导出【每个文件只能写一次】
    export default Animal;

    //文件B:导入
    import Animal,* as api from './output.js';
    let ani = new Animal('jack')
    console.log(ani);
    api.print();
    api.play();
    api.show();

    //文件C:导入
    import Animal,{print,play,show} from './output.js';
    let ani = new Animal('jack')
    console.log(ani);
    print();
    play();
    show();

fs模块【文件操作模块】
01 - 读取文件(异步)
  • 语法:fs.readFile(filename, [options], callback)

  • filename 是文件名;[options] 是可选的参数 , 为一个对象,用于指定文件编码(encoding)及操作方式(flag);callback 是回调函数,传递异常err 和文件内容 data 的 2 个参数

        var fs = require("fs"); // 引入 fs 模块
        fs.readFile(".test.txt",”utf-8,function(err,data){ 
        if(err){
            throw err;
        }
        // 读取文件成功
        console.log(data);
        });
    
    
02 - 读取文件(同步)
  • 语法:fs.readFileSync(filename, [options])

  • filename 是文件名;[options] 是可选的参数 , 为一个对象,用于指定文件编码(encoding)及操作方式(flag);

        var fs = require("fs"); // 引入 fs 模块
        var result = fs.readFileSync(".test.txt",”utf-8);
        console.log(result);
    
    
03 - 写入文件(异步)
  • 语法:fs.writeFile(filename,data,[options],callback)

  • filename是文件名称;data是要写入文件的数据;[options]是一个对象为可选参数,包含编码格式(encoding),模式(mode)以及操作方式(flag);callback 是回调函数

        var fs = require("fs");
        var data = " 嘿嘿嘿”;
        
        // 写入文件内容,如果文件不存在则创建文件
        fs.writeFile("./test/11.txt",data,{"flag":"a"},function(err){
            if(err) throw err;
        });
    
    
04 - 写入文件(同步)
  • 语法:fs.writeFileSync(file, data[, options])

  • filename是文件名称;data是要写入文件的数据;[options]是一个对象为可选参数,包含编码格式(encoding),模式(mode)以及操作方式(flag)

        var fs = require("fs");
        var data = " 嘿嘿嘿”;
        
        // 返回undefined
        fs.writeFileSync("./test/11.txt",data,{"flag":"a"});
    
    
05 - 流式文件写入【适合大文件的写入,性能高,不易导致内存溢出】
    var fs = require("fs");
    //1.创建一个可写流
    var ws = fs.createWriteStream("hello3.txt",{flags:'a'});
    //2.绑定打开和关闭的一次性事件ws.once("open",function () {console.log("流打开了");});
    ws.once("close",function () {console.log("流关闭了");});
    //3.通过ws向文件中输出内容
    ws.write("百度");
    ws.write("IT培训");
    //4.关闭流
    ws.end();

06 - 流式文件读取【适合大文件的读取,性能高,不易导致内存溢出】
    var fs = require("fs");
    const rs = fs.createReadStream('./我的自白书.txt','utf-8')
    //onData事件,代表读取中
    rs.on('data',(data)=>{
        //读取的过程中,同时写入
        ws.write(data)
    })
    //onClose事件,表示读取结束
    rs.on('close',function(){
        //读取结束后,关闭ws
        ws.end();
    })

07 - 删除文件(异步)
  • 语法:fs.unlink(path, callback)

  • path是文件路径;callback 是回调函数(参数只有一个error对象)

        var fs = require("fs");
    
        // 假设 'path/file.txt' 是一个普通文件。
        fs.unlink('path/file.txt', (err) => {
        if (err) throw err;
            console.log('文件已删除');
        });
    
    
08 - 删除文件(同步)
  • 语法:fs.unlinkSync(path)

  • path是文件路径

        var fs = require("fs");
        // 没有返回值
        fs.unlinkSync('path/file.txt');
    
    
09 - 创建文件夹(异步)
  • 语法:fs.mkdir(path, [mode], callback)
    path 是需要创建的目录;
    [mode] 是目录的权限(不支持windows平台);
    callback 是回调函数

        var fs = require("fs");
        fs.mkdir("./wenjianjia",function(err){
            if(err){
                throw err;
            }
            console.log(" 创建目录成功 ");
        })
    
    
10 - 读取目录(异步)
  • 语法:fs.readdir(path, callback)
    path 是需要读取的目录;callback 是回调函数.
    会返回error和一个数组,数组中是当前根目录下的所有文件夹名称和文件名称。

        var fs = require("fs");
        fs.readdir("./wenjianjia",function(err,files){
        if(err){
            throw err;
        }
        console.log(files);
        });
    
    
11 - 删除目录(异步)
  • 语法:fs.rmdir(path, callback)
    path 是需要删除的目录;callback 是回调函数.
    注意:只能删除空目录

        var fs = require("fs");
        fs.rmdir("./wenjianjia",function(err){
        if(err){
            throw err;
        }
        });
    
    
12 - 查看文件与目录的信息
  • 语法:fs.stat(path, callback)
    path 要查看目录 / 文件的完整路径及名;[callback(err, stats)] 操作完成回
    调函数,err 错误对象,stats fs.stat 一个对象实例,提供如 :isFile, isDirectory 等方法。

        var fs = require('fs');
        fs.stat('./wenjianjia',function(err,stats){
            if(stats.isDirectory()){
                console.log('文件夹');
            };
        })
    
    
13 - 查看文件与目录是否存在
  • 语法:fs.exists(path, callback)
    path要查看目录 /文件的完整路径及名;[callback(exists)]操作完成回调函数,exists true 存在,false 表示不存在。

        var fs = require("fs");
        fs.exists("./test/",function(exists){
        if(exists){
            console.log(" 文件夹存在 ");
        }else{
            console.log(" 文件夹不存在 ");
        }
        });
    
    
14 - 重命名文件
  • 语法:fs.rename(oldPath,newPath,callback)
    异步地将 oldPath 上的文件重命名为 newPath 提供的路径名. 如果 newPath 已存在,则覆盖它

        let fs = require('fs')
        fs.rename('./foo.txt','./bar.txt',function (err) {
            if(err){
                throw err
            }
            console.log('修改成功')
        })
    
    
URL模块L
  • 一个完整的URL地址分为:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHWsqQ1Q-1634128183222)(images/20210922171659.png)]
01 - parse函数
  • 语法:url.parse(urlStr[, parseQueryString])
    urlStr 输入一个 url 字符串;parseQueryString(默认为 false),如为true,则 urlObject.query 为解析后的对象

        var url = require("url");
        var path ="http://user:pass@host.com:8080/p/a/t/h?query=string#hash";
        var query= url.parse(path).query; //query=string
        var queyr= url.parse(path,true).query; //{query:'string'}
    
    
path模块
  • 处理路径的工具模块
01 - path.basename
  • 获取路径中的文件名,第一个参数 path 为必须指定的参数,ext 参数为可选参数。path 参数值必须为一个文件的完整路径,可以是相对路径,也可以使绝对路径。ext 参数值用于在方法所返回的文件名中去掉文件的扩展名

        var path = require("path");
        var fileName = path.basename("./test/aa.txt");
        console.log(fileName); // aa.txt
        var name = path.basename("./test/aa.txt",".txt");
        console.log(name);      //aa
    
    
02 - path.dirname
  • 提取出一个路径中的祖先路径

        var path = require("path");
    
        var dirname = path.dirname("./test/i/aa.txt");
        console.log(dirname); //./test/i
    
        var dirname = path.dirname('./test/i');
        console.log(dirname); //./test
    
    
03 - path.extname
  • 获取一个路径中的扩展名

        var path = require("path");
    
        var extname = path.extname("./test/aa.txt");
        console.log(extname);//.txt
    
    

day12 - Node模块(二)

继续Path模块
04 - path.join
  • path.join([path1], [path2], […])
    将多个参数值字符串结合成一个路径字符串
05 - path.resolve
  • path.resolve([path1], [path2], […])
    把一个路径或路径片段的序列解析为一个绝对路径,类似cd命令
06 - join和resolve的对比
    var path = require("path");
    path.join('/a', '/b') // Outputs '\a\b'
    path.resolve('/a', '/b') // Outputs 'H:\b'

07 - path.normalize
  • 于将非标准路径的字符串转化成标准路径字符串

        var path = require("path");
        var normalize = path.normalize("../a//b//d//..//c//d/")
        console.log(normalize);//..\a\b\c\d
    
    
querystring模块
01 - querystring.parse
  • querystring.parse(str[, sep[, eq[, options]]])

  • 是将一个字符串反序列化为一个对象

  • str 指需要反序列化的字符串,sep(可选)指用于分割 str 这个字符串的字符或字符串,默认值为 “&”;eq(可选)指用于划分键和值的字符或字符串,默认值为 “=”;options(可选)该参数是一个对象,里面可设置 maxKeys 属性:传入一个 number 类型,指定解析键值对的最大值,默认值为 1000,如果设置为 0 时,则取消解析的数量限制

        var querystring = require("querystring");
        var newObj=querystring.parse("site=QQ&url=http://www.qq.com/");
        var queryObj=querystring.parse("site=QQ#url=http://www.qq.com/
        #age=5","#",null,{maxKeys:2});
    
    
02 - querystring.stringify
  • querystring.stringify(obj[, sep[, eq[, options]]])

  • 将一个对象序列化成一个字符串

  • 数 obj 指需要序列化的对象;sep(可选)用于连接键值对的字符或字符串,默认值为 “&”;eq(可选)用于连接键和值的字符或字符串,默认值为 “=”;

        var querystring = require("querystring");
        var str = querystring.stringify({name:"baidu",sex:"man"});
        console.log(str);        //name=baidu&sex=man
        console.log(queryStr);    //name*baidu|sex*man
    
    
03 - querystring.escape
  • 使传入的字符串进行编码

        var querystring = require("querystring");
        var str = querystring.escape("name= 百度 ");
        console.log(str);
    
    
04 - querystring.unescape
  • 将含有 % 的字符串进行解码

        var querystring = require("querystring");
        var str = querystring.unescape("name%3D%E4%BC%98%E5%B0%B1%E4%B8%9A");
        console.log(str);
    
    
创建HTTP服务
    //创建一个http服务(就可以通过网址+端口号来访问了)
    //1.引入http模块
    const http = require('http')
    const fs = require('fs')
    //2.通过http对象创建Server
    http.createServer(function(req,res){
        console.log(req.url);
        let data=null;
        if(req.url=='/'){
            //设置响应头,类型为text/html,可以解析html标签
            res.writeHead(200,"ok",{'Content-Type':'text/html;charset=utf-8'})
            //文件读取:网页
            data = fs.readFileSync('./index.html','utf-8')
            //将网页内容输出给浏览器
        }else if(req.url.endsWith('.css')){
            //设置响应头,类型为text/html,可以解析html标签
            res.writeHead(200,"ok",{'Content-Type':'text/css;charset=utf-8'})
            data = fs.readFileSync('.'+req.url,'utf-8');//  ./public.css
        }else if(req.url.endsWith('.js')){
            res.writeHead(200,"ok",{'Content-Type':'text/javascript;charset=utf-8'})
            data = fs.readFileSync('.'+req.url,'utf-8');//  ./public.css
        }else{
            res.writeHead(200,"ok",{'Content-Type':'image/x-icon'})
            data = fs.readFileSync('.'+req.url);//  图片
        }
            res.write(data);
            res.end();//关闭[如果不关闭,页面就会一直加载中,一直等待]
    }).listen(8888)
    console.log('server startup on 8888')
    //3.监听端口:8888
    //4.访问地址:http://localhost:8888/

day13

学员管理系统,增删改登录

补充:
01 - 概念/安装/运行
  1. node.js是一个基于chrome V8引擎的js运行时(运行时指的就是“运行环境”)。
  2. 浏览器的内核需要分为,渲染引擎、JS引擎。
  3. 安装:略(就是下一步!)
  4. 运行:略(cmd窗口:node 名.js)
02 -编码/解码
const querystring = require('querystring')\

// 原因:亚洲文字,特殊符号在网络传输中容易乱码

// 编码
let res = querystring.escape('哈哈=123')

// 解码
let res2 = querystring.unescape('%E5%93%88%E5%93%88=123')

day14 - Express框架

Express

NodeJS最有名的框架

原生Node开发存在的问题
  • 呈递静态页面不方便,需要处理每个HTTP请求、考虑304问题及缓存问题等
  • 路由处理代码不直观不清晰,需要写很多正则表达式和字符串函数
  • 不能集中精力写业务,要考虑很多其他的东西
Express安装
    npm install express 
    //或
    yarn add express
    //或
    cnpm install express

基本结构
    //app.js
    var express = require("express");
    var app = express();
    //任何请求方式,任何地址都会进入,可用作拦截器使用
    app.all("*",function(req,res,next){        
        next();
    })
    //匹配路由时,可以自动过滤掉query和hash部分
    app.get('/', function (req, res) {  
        //res.sendFile(); 发送页面给浏览器
        res.sendFile(__dirname + '/post_client.html'); 
        //res.send(); 发送数据给浏览器
    });
    app.listen(8000)

使用express-generator脚手架
  1. 安装工具:npm install express-generator -g

  2. 生成项目:express —view=ejs myapp

  3. 安装依赖:cd myapp && npm install

  4. 启动项目:set DEBUG=myapp:* & npm start

  5. 打开浏览器:http://localhost:3000/

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wpc05ApJ-1634128183223)(images/Express脚手架.png)]

在Express中获取GET请求数据
    var express = require("express");
    var app = express();
    app.get("/",function(req,res){
        console.log(req.query);
        res.send(req.query);
    });
    app.listen(3000);

在Express中获取POST请求数据
    var express = require("express");
    var bodyParser = require('body-parser')
    var app = express();
    app.use(bodyParser.urlencoded({ extended: false }))
    app.get("/",function(req,res){
        res.send(req.body.username);
    });
    app.listen(3000);

Koa2

近两年比较流行的框架

补充:
01 - express 默认导入,静态资源
    // 默认引入
    const express = require('express');
    const app = express();

    const path = require('path');
    // 处理静态资源,要指定静态资源在哪里{assets文件夹中}(js,css,font,媒体)
    app.use(express.static(path.ressolve(__dirname,'assets')));

day15 - 文件上传与RestFul

文件上传
  1. 安装:

    npm install multer
    
    
  2. 配置:app.js

    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    //【要写在业务模块的前面】
    app.use(multer({dest: '/tmp/'}).array('myFile', 10));
    //业务模块【indexRouter里面的路径可以直接访问,userRouter里的路径需要在前面加/users】
    app.use('/', indexRouter);
    app.use('/users', usersRouter);
    
    
  3. 上传后端:/routes/users.js

    //页面访问路径:/users/user/add
    router.post('/user/add',function(req,res){
      //1000 - 9999
      var max = 9999;
      var min = 1000;
      req.files.forEach(f=>{
        //1.拼接一个新的文件名:毫秒值+随机数+后缀名组成
        var t = Date.now();
        var r = parseInt(Math.random()*(max-min))+min;  //生成一个四位随机数
        var ext = path.extname(f.originalname);//获取源文件的后缀名   .jpg
        var name = t + "" + r + ext;
        //2.读取原始文件
        var data = fs.readFileSync(f.path);
        //3.将图片写入到我们指定的文件夹中
        //__dirname:桌面\Express-app\routes
        //拼完的路径:桌面\Express-app\photo\123123213123.jpg
        fs.writeFile(path.resolve(__dirname,'../public/images',name),data,function(err){
          if(err){
            console.log("报错了:",err);
            throw err;
          }
          //如果照片上传成功,再将学员姓名添加到数组中,并返回success
          //POST的参数:req.body.参数名
          console.log("学员姓名:",req.body.username);
          //将学员姓名和学员照片名以对象形式存储在数组里
          students.unshift({
            username:req.body.username,
            photo:name
          });
        })
      })
      res.send("success");
    })
    
    
  4. 上传前端:/views/add.html

  5. html部分

    <input type="text" name="username" id="username" placeholder="请填写学员姓名"><br>
    <input type="file" name="userphoto" id="userphoto"><br>
    <span></span>
    <button>提交</button>
    
    

    js部分

    $("button").click(function(){
            var username = $("#username").val();
            var userphoto = document.getElementById("userphoto");
            var formData = new FormData();
            formData.append('username',username);
            formData.append('userphoto',userphoto.files[0])
            $.ajax({
                    url:'/users/user/add',
                    method:'POST',
                    data:formData,
                    processData:false, //不要去处理文件数据内容
                    contentType:false, //告诉jQuery不要去设置Content-Type请求头
                    success:function(res){
                        console.log(res);
                    },
                    xhr:function(){
                        let xhr = $.ajaxSettings.xhr();
                        if(xhr.upload){
                            //上传进度查看
                            xhr.upload.addEventListener('progress',function(e){
                                var percent = parseInt(e.loaded / e.total * 100);
                                $("span").html(percent+"%");
                            })
                        }
                        return xhr;
                    }
                })
        })
    
    
ESTFul API4
  • RESTful架构,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。每一个URI代表一种资源;
    客户端和服务器之间,传递这种资源的某种表现层;
    客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”

  • GET http://www.baidu.com/api/user # 获取列表
    POST http://www.baidu.com/api/user # 创建用户
    PUT http://www.baidu.com/api/user/{id} # 修改用户信息
    DELETE http://www.baidu.com/api/user/{id} # 删除用户信息

  • 在前端传递参数:

    工号为12345

    $.ajax({
        url:'/teacher/12345',
        method:'GET',
        success:function(res){
            console.log(res);
        }
    })
    
    

    在Node中获取参数:

    app.get("/teacher/:gonghao",function(req,res){
        res.send(" 老师工号 " + req.params.gonghao);
    });
    
    
前后端分离架构模式
  • 分离原则
    1. 前端静态化
    2. 后端数据化
    3. 平台无关化
    4. 构架分离化
  • 分离模式的优势
    1. 前后端流量大幅减少
    2. 表现性能的提高
    3. 前后端平台无关和技术无关
    4. 安全性方面的集中优化开发的分离和构架的分离

day16 - MongoDB

数据库(DataBase)
  • 传统数据库:MySQL、SQL Server、Oracle【关系型数据库】
  • 非关系型数据库:MongoDB、Redis、MemoryCache
非关系型数据库的应用场景
  • 日志管理
  • 无关联的数据信息
  • 数据量特别大
传统数据库层级结构
  • Database->Table->Row
MongoDB数据库层级结构
  • Database->Collection->document
mongoDB默认端口号:
  • 27017
常用命令
打开CMD->输入:mongo 回车:

show dbs【查看所有数据库名称列表以及所占硬盘空间】

use 数据库名【切换到指定的数据库中,如果不存在则创建并切换】

db【查看当前的数据库名称】

show tables/show collections 【查看当前数据库中所有集合】

db.createCollection(“集合名称”) 【创建一个空集合】

db.集合名称.insert({key1:value1,key2:value2}) 【给这个集合插入一条数据】

db.集合名称.insert([{key1:value1},{key2:value2}])【给这个集合插入多条数据】

db.集合名称.find() 【查看当前集合的全部数据】

db.集合名称.remove({key:value}) 【删除符合指定key-value条件的数据】

db.集合名称.drop() 【删除当前集合】

db.集合名称.update({筛选条件},{更新的内容},{multi:true})【不加第三个参数,只更新一条】

db.集合名称.update({筛选条件},{$set:{更新的内容}},{multi:true})【$set:只更新要修改的内容,其他内容不变,如果要更新的内容之前没有,则添加进去】

db.集合名称.update({筛选条件},{$unset:{更新的内容}}) 【$unset:删除某些属性】

db.student.find({age:{$lt:20}}) 【筛选age小于20的学生】

db.student.find({age:{$lte:20}}) 【筛选age小于等于20的学生】

db.student.find({age:{$gte:20}}) 【筛选age大于等于20的学生】

db.student.find({age:{$gt:20}}) 【筛选age大于20的学生】

db.student.find({age:{$ne:20}}) 【筛选出年龄不是20的学生】

db.student.find({$or:[{sex:’女’},{age:{$lte:20}}]}) 【筛选出性别是女的或者年龄小于等于20的学生】

db.student.findOne({筛选条件}) 【只查找一条数据】

导出
mongoexport -d 数据库名称 -c 集合名称 -o “E:\mongosql.json”

导入
mongoimport -d 数据库名称 -c 集合名称 —file “E:\mongosql.json” —type=json

mongoose模块使用步骤
  1. 安装

        npm install mongoose@5.0.15
    
    
  2. 创建DB.js文件【负责连接数据库】

        const mongoose = require('mongoose');
        /**
         * 数据库连接
         */
        mongoose.connect('mongodb://127.0.0.1/student_manage');
        mongoose.connection.on('connected',function(){
            console.log('mongodb connected')
        })
        mongoose.connection.on('error',function(){
            console.log('mongodb error')
        })
        mongoose.connection.on('disconnected',function(){
            console.log('mongodb disconnected')
        })
        module.exports = {
            mongoose
        }
    
    
  3. 创建数据库集合模型【Schema、Model】例如:Student.js

        const db = require('./DB');
        /**
         *  创建学生模型【规则】
         */
        var StudentSchema = db.mongoose.Schema({
            name:{type:String,required:true},
            age:{type:Number,min:1,max:200},
            sex:{type:String,enum:['男','女']},
            tel:{type:Number},
            tid:{type:String}
        },{versionKey: false})
        //这里的student ,对应数据库里面叫做 students的表
        var Student = db.mongoose.model('student',StudentSchema)
        module.exports = Student;
    
    
  4. 通过导出的实例完成CRUD【增删改查】

    添加:

        Student.create({
            name:'小刘',
            age:20,
            sex:'女',
            tel:1012031,
            tid:'12313'
        },function(err,data)
        //或
        var s = new Student({
            name:'陈小姐',
            age:22,
            sex:'女',
            tel:123123,
            tid:"123123"
        })
        s.save(function(err,res){})
    
    

    更新:

        Student.create({
            name:'小刘',
            age:20,
            sex:'女',
            tel:1012031,
            tid:'12313'
        },function(err,data)
        //或
        var s = new Student({
            name:'陈小姐',
            age:22,
            sex:'女',
            tel:123123,
            tid:"123123"
        })
        s.save(function(err,res){})
    
    

    删除:

        Student.deleteMany({name:'petper'},function(err,res)
        //或
        Student.findByIdAndRemove(id,function(err,res)
    
    

day17 - Monse高级应用

在mongoose里面查询

语法:
模型.find(查询条件,显示字段,回调函数)
例子:

    //显示字段:1代表显示该字段,0代表不显示该字段
    //res:是一个数组
    Student.find({name:'jack'},{name:1,age:1},function(err,res))
    
    //查询年龄在 21 到 65 之间的学员
    Student.find({age: {$gte: 21, $lte: 65}}, callback)
    
    //查询年龄不等于50的学员
    Student.find({age: {$ne: 50}}, callback)

    //查询名字中包含m的学员
    Student.find({'name':{$regex:/m/i}}, function(err, res)

模型.count(查询条件,回调函数)
例子:

    //res:返回查询结果的个数
    Student.count({name:'jack'},function(err,res))

模型.findById(id值,回调函数)
例子:

    //根据id查询唯一的记录
    Student.findById('wdadw',function(err,res){})

分页查询:
例子:

    var pageSize = 5;                          //一页多少条
    var currentPage = 1;                //当前第几页
    var sort = {'logindate':-1};            //排序(1 升序,-1降序)
    var condition = {};                        //条件
    var skipnum = (currentPage - 1) * pageSize;   //跳过数
    User.find(condition).skip(skipnum).limit(pageSize).sort(sort).exec(fn)

关联查询:
例子:

    //学生表的tid关联了老师表的_id
    Student.aggregate([
        {
            $lookup:{
                from:'teachers',
                localField:'tid',
                foreignField:'_id',
                as:'results'
            }
        }
    ]).exec(function(err,result){
        if(err){
            console.log(err);
        }
        console.log(result)
    })

HTML页面->Node服务->MongoDB

MVC
M:Model【Student.js、Teacher.js】
V: View 【页面】
C: Controller 【控制器】:业务处理代码

day18 - 跨域与JWT

同源策略

协议名、域名、端口 三者都保持一致

跨域

协议名、域名、端口只要有一个不同,就是跨域请求

http://127.0.0.1:3000和http://127.0.0.2:3000
http://127.0.0.1:3000和http://127.0.0.1:3001
http://127.0.0.1:3000和ftp://127.0.0.1:3001

跨域什么时候会失败呢?

Ajax请求时才会失败
普通的HTML标签不会失败:

<form><img src=""><script src=""><iframe>

如何解决跨域失败问题呢?

JSONP
CORS【跨域资源共享】
Nginx【应用服务器】

JSONP跨域原理是什么?

本质不是ajax,它并没有使用XMLHttpRequest对象,用的是动态创建script标签

JSONP有啥缺点?

只支持GET方式、书写比较复杂

JSONP优点?

兼容性非常好

CORS优点

支持所有请求方式:GET、POST、PUT、DELETE

md5加密
    const crypto = require('crypto')
    var md5 = crypto.createHash('md5');
    function MD5(content){
        var str = md5.update(content).digest('hex')
        return str;
    }
    var pass = MD5("123")

JWT(Json WebToken)

使用流程:

  1. 安装express-jwt和jsonwebtoken
  2. 设置一个用于生成token和验证token的KEY值
  3. express-jwt验证token是否正确
  4. 通过username和password生成口令,设置过期时间
  5. 将口令发给页面
  6. 页面获取token,然后将token保存到本地
  7. 发起任意请求的时候都要在http的头部添加token
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值