day5

97 阅读5分钟

1.两种数学方法

1.Math.random()*n  //0-n之间的所有随机数 
2.Math.random() //0-1之间的所有随机小数

2.参数的作用

作用:为了使函数抽象,函数内部的内容独立,可以通过加入参数让函数执行不同的特征     多态!

a,b,c就是形参 
1,2,3就是实参 
实参按照顺序赋值给形参 
如果对应的形参没有实参值,这个形参的值是undefined

3.纯函数

当函数中不使用外部的全局变量,或者不改变外部的全局变量时,这个函数就叫做纯函数
例:function randomColor(){
   var str="#";
   for(var i=0;i<6;i++){
   str+=(~~(Math.random()*16)).toString(16); //0-16之内随机数  ~~取整  转16进制
        }
   return str;//return 返回str
    }
   var color=randomColor();
   console.log(color)

4.参数分为三种类型

   1、必填参数
   2、初始值参数(ES6)
   3、可选参数        
   ES5中真的参数是没有固定的
   
   参数也可以有顺序
   例:b=1是默认值参数  
   当给入b值时,b的值就是对应的值,如果没有给值时,b的值是默认值1 
   function fn(a,b=1,c){
   console.log(a,b,c);  //a必填参数  b默认参数  c可选参数因为没给  
   } 
   fn(5);
   fn(5,2);//a=5 b=1 c=undefind

5.参数的数量问题(arguments)

参数有时候是无限的 ES5  
   1.使用arguments来完成参数调用
   2.ES6 ...arg来完成参数调用
   
1.ES5  arguments.length是参数长度,这个是实参长度,也就是实参数量
   例:function getMinAndMax(){
        var obj={min:arguments[0],max:arguments[0]};
        for(var i=1;i<arguments.length;i++){
            obj.min > arguments[i] ? obj.min=arguments[i] : 1;  // :1 代表不操作
            obj.max <arguments[i] ? obj.max=arguments[i] : 1;
        }
        console.log(obj);
    }
    
2.ES6 ...arg 这种方式使用多个参数
   例:function getMinAndMax(...arg){
        var obj={min:arg[0],max:arg[0]};
        for(var i=1;i<arg.length;i++){
            obj.min > arg[i] ? obj.min=arg[i] : 1;
            obj.max <arg[i] ? obj.max=arg[i] : 1;
        }
        console.log(obj);
    }

5.1上述两种方式的区别

 1. 全部参数 ES5
    function fn(a){
        console.log(arguments);
    }
    fn(1,2,3);

 2. ...arg 剩余参数 ES6
    function fn1(a,...arg){
        console.log(a,arg)
    }
    fn1(1,2,3)
区别:第一种全部赋值给arg 第二种方法 1传给a 2.3赋值给arg
    ES5 和 ES6的写法可以混合

6.引用地址问题

参数引用地址改变 造成结果的改变
例: var obj={a:1,b:2}
    // 全局变量将引用地址赋值给局部变量
    function fn(obj){
        // 修改这个引用地址中a属性的值
        obj.a=10;
    }
    fn(obj);
    console.log(obj);//{a: 10, b: 2}

例: var obj1={a:1,b:2}
    // 全局变量将引用地址赋值给局部变量
    function fn1(obj1){
        // 将obj1变量赋值了一个新的引用地址,obj1和全局obj1的引用地址不相同了
        obj1={a:10,b:1};
    }
    fn1(obj1);
    console.log(obj1);//{a: 1, b: 2}

7.iterator  迭代器

function fn(){
       // console.log(arguments)
       console.log(arguments.callee);//当前函数
       // 调用当前函数作用域中的上下文执行函数,如果是window则返回null
       console.log(arguments.callee.caller); //此处和下面那句是一个意思
      // console.log(fn.caller);
    }
    
 function fn1(){
        fn();
    }

 fn1();
 fn(); //函数在哪调用 就执行谁

8.随机透明度案例

希望可以随机透明度  如果透明度设置为1 则不透明,如果透明度设置为小于0,则透明度为0
如果不设置则随机透明,或者设置1以下0以上,
希望设置固定色彩时,该色彩固定,不设置该色彩时,这个颜色随机
例:function randomColor(alpha,r,g,b){
     var str="rgba(";
     or(var i=0;i<4;i++){
         if(arguments[i]===undefined){
             i===0 ? alpha=(Math.random()).toFixed(2) : str+=~~(Math.random()*256);
            }else if(arguments[i]<0){
             i===0 ? alpha=0 : str+="0";
            }else if(i===0 ? arguments[i]>1 : arguments[i]>255){
             i===0 ? alpha=1 : str+="255";
            }
            if(i>0) str+=",";
        }
        str+=alpha+")";
        return str;
        if(alpha===undefined) alpha=(Math.random()).toFixed(2);
        if(alpha<0) alpha=0;
        if(alpha>1) alpha=1;
        if(r===undefined) r=~~(Math.random()*256);
        if(r>255) r=255;
        if(r<0) r=0;
        if(g===undefined) g=~~(Math.random()*256);
        if(g>255) g=255;
        if(g<0) g=0;
        if(b===undefined) b=~~(Math.random()*256);
        if(b>255) b=255;
        if(b<0) b=0;
        return `rgba(${r},${g},${b},${alpha})`;
    }
   var color= randomColor(2,256);
   console.log(color)
   
代码简化:function randomColor(alpha,r,g,b){
        if(alpha===undefined) alpha=(Math.random()).toFixed(2);
        if(alpha<0) alpha=0;
        if(alpha>1) alpha=1;
        
        if(r===undefined) r=~~(Math.random()*256);
        if(r>255) r=255;
        if(r<0) r=0;
        
        if(g===undefined) g=~~(Math.random()*256);
        if(g>255) g=255;
        if(g<0) g=0;
        
        if(b===undefined) b=~~(Math.random()*256);
        if(b>255) b=255;
        if(b<0) b=0;
        return `rgba(${r},${g},${b},${alpha})`;

9.return用法

1、返回值
2、跳出函数,不执行return后面的语句

1.1任何函数执行后都会有返回值,如果使用return返回结果时,函数则返回这个内容如果没有使用return ,或者return后面没有别的内容时,返回undefined
    function fn(){
        return 1;
    }
    var a=fn();
    console.log(a)

1.2返回值只能返回一个.如果要返回多个时,我们可以通过返回对象或者返回数组来返回多个值
    function fn(){
        return {a:1,b:2};//当每个值需要说明是谁的时,返回对象
    }

    function fn(){
        return [1,2];//如果仅仅返回值,不需要考虑是谁的,可以使用返回数组
    }
    
2.1跳出
    function fn(){
    console.log("a");
    return;
    console.log("b");//永远不会执行
       }    

9.1工厂模式

 function getObj(name,age){
//  var obj={name:name,age:age};
// 如果变量名与属性名相同时,可以使用下面的方法
//    var obj={name,age};
//    return obj;
// 因为每次返回的都是新对象  新的引用地址
    return {
         name,
         age
        }
    }

 var o=getObj("谢天",30);
 var o1=getObj("谢天",30);
 console.log(o===o1); //false  因为每次返回的都是新对象 虽然数据相同但是引用地址不同

9.2单例模式

例:var instance;
   function getInstance(){
    return instance || {name:'谢天',age:30};
   }
   var o=getInstance();
   var o1=getInstance();
   console.log(o===o1);  //false 因为 instance是undefind 后面都是获取的值 地址还是不同

例:var instance;
   function getInstance(){
    return instance || (instance={name:'谢天',age:30});
     }
   var o=getInstance();
   var o1=getInstance();
   console.log(o===o1);  //true

9.3返回值的变种特征

例:function fn(f,a){
    if(f(a)){
        console.log("a");
    }else{
        console.log("b");
    }
}

fn(function(a){
    return a>10;
},5)  //b 这里是判断条件在前 a的赋值在后

9.4小知识

new Error("错误信息")
new TypeError("类型错误信息"),比如应该是字符型,结果给了数值型,属于类型错误
new RangeError("范围错误")表示超出范围,比如要求是0-100,结果超出这个返回了

例.真值缩小
var arr=["零","一","二","三","四","五","六","七","八","九","十"];
function getCNNumber(num){
    // throw new Error("aaa");// 返回错误信息,并且中断不继续执行代码
    if(num<0 || num>=100) throw new RangeError("num是"+num+",这个数字超出范围,必须是0-100之间");
    if(num<11) return arr[num];
    if(num%10===0) return arr[num/10]+"十";
    if(num<20) return "十"+arr[num%10];
    return arr[~~(num/10)]+"十"+arr[num%10];
}
var n=getCNNumber(5);//五
var n=getCNNumber(10);//十
var n=getCNNumber(15);//十五
var n=getCNNumber(20);//二十
var n=getCNNumber(25);//二十五
//>=100   <0 报错
console.log(n);

10.什么是回调

回调函数
    + 是一种函数的调用方式
    + 必然涉及到两个函数的使用(调用)
    + 有一个 函数A: 我们封装的函数, 在这里面可能封装了遍历或者异步
    + 有一个 函数B: 我们给到 函数A 的锦囊(目的: 我要做的事情)
    + 当调用 函数A 的时候, 把 函数B 当做实参传递进去
      => 函数A 的形参接受的就是 函数B 的存储地址
    + 说: 函数B 是 函数A 的回调函数
    
例:
回调函数的概念
我的封装代码
function A(fn) {
  // fn 形参, 接受的就是全局 B 函数的存储地址
  // fn() 和 B() 调用的是一个函数
  fn() // 把锦囊执行掉了
}
// 我的 锦囊
function B() {}
// 调用 A 函数
A(B)

私人解释:把一个函数作为参数传入到另外一个函数中,并在另外一个函数执行,叫做回调 (回调函数不能赋值 不能传参)
例:function fn(f){
      f();
   }

  function fn1(){
      console.log("aa")
   }
  fn(fn1);
  
  
1.封装遍历调用回调
function A(arr, fn) {
  // fn 就是 全局 B 函数
  // 直接遍历 arr
  for (var i = 0; i < arr.length; i++) {
    // 这个位置的代码, 会根据 arr 内的数量执行多少次
    // 随着循环, arr[i] 就是数组内的每一个数据
    fn(arr[i], i, arr) // 数组内有多少个数据, 执行多少次
  }
}

function B(item, index, arr) {
  console.log('我是一个作为锦囊的函数', item, index, arr)
}

A([100, 200, 300, 400], B)

10.1回调的三种情况

1、异步时,通过回调,在异步完成后执行回调函数
2、当某件事件处理完成后调用回调函数
3、把条件作为内容分离或者把执行方式分离,通过回调函数完成
10.1.1异步后执行
例:setTimeout(timeHandler,1000);

   function timeHandler(){
       console.log("aaa") //过段时间执行
    }
10.1.2当某件事件处理完成后调用回调函数
例:function fn(a,b,f){
   var s=a+b;
     f(s);
    }

function fn1(s){
   console.log(s);
    }

fn(5,7,fn1); //12
10.1.3把条件作为内容分离
   例:function fn(f){
        if(f(18)){
            console.log("aa")
        }else{
            console.log("bb")
        }
    }

    fn(function(a){
        return a>10    //aa
    })
10.1.4把执行方式分离
  例:function fn(a,b,f){
        return f(a,b);
    }
    function a(a,b){
        return a+b;
    }
    function b(a,b){
        return a-b;
    }
    function c(a,b){
        return a*b;
    }
    function d(a,b){
        return a/b
    }
  var s=fn(4,6,c);
  console.log(s)   //24
10.1.5两个函数之间互相调用完成递归的作用
例:var a=1;
  function fn(f){
    a++;
    f(fn);
}

function fn1(f){
    console.log(a);
    if(a<3) f(fn1);
}
fn(fn1);//2   3
10.1.6回调地狱
回调地狱的原因是,当人们试图以一种从上到下的视觉方式执行JavaScript的方式编写JavaScript时
就是吊起来没完 就一直套
例:function showRed(fn1,fn2){
    setTimeout(function(){
        console.log("红灯");
        fn1(fn2,showRed);
    },2000)
}
function showYellow(fn1,fn2){
    setTimeout(function(){
        console.log("黄灯")
        fn1(fn2,showYellow);
    },1000)
}
function showGreen(fn1,fn2){
    setTimeout(function(){
        console.log("绿灯")
        fn1(fn2,showGreen);
    },1000)
}
showRed(showYellow,showGreen)

简写:就下面这种破造型
例:function showLight(){
    // 回调地狱
   setTimeout(function(){
       console.log("红灯")
        setTimeout(function(){
            console.log("黄灯");
            setTimeout(function(){
                 console.log("绿灯")
            },2000);
        },1000);
    },2000);
}
showLight();

11.递归

 /*
  函数的递归调用(慎用)
    + 是一种函数的调用方式
    + 一个函数调用了自身, 并且设置了正确的返回条件
    + 那么这个函数调用方式, 就叫做递归调用函数

  写递归函数(总结规律)
    1. 书写一个函数
    2. 先写折返点条件
    3. 按照规律书写递进条件, 不要忘记 return
*/

例:
// 递归求阶乘
function fn(n) {
  // n 就是要求阶乘的数字

  // 当 n 为 1 的时候, 不需要递进了, 可以直接返回结果
  if (n === 1) return 1

  // 4 的阶乘 => 就是 4 * 3的阶乘
  return n * fn(n - 1)
}

// 将来我需要求 10 的阶乘 => fn(10)
// 将来我需要求 9 的阶乘 => fn(9)
// 求一个 4 的阶乘
var res = fn(4)
console.log(res)


递归=>在当前函数内调用自身函数
  例:var a=1;
    function fn(){
        a++;
        if(a<10) fn();
    }

  例:var a=1;
    function fn(){
        a++;
        if(a<4) fn();//尾递归  后面没有东西了
    }
    
 递归一般用于
    1、深度遍历时
    2、多次处理时

11.1 广度遍历 和 深度遍历

例: var obj = {
         a:1,
         b:2,
         c: {
             d:3,
             f:{
                 g:5,
             }
         },
         h:6
     }

    for(var key in obj){
        console.log(key)  //1.广度遍历 仅遍历第一层
    }


    function showObjValue(obj){
        for(var key in obj){                   //遍历obj
            // console.log(key,obj[key])    //健名 每一个属性值  里面会有对象c:{a:{}}的情况
            if(typeof obj[key]==="object"){   // 判断 如果是对象的话也要每个都遍历
                showObjValue(obj[key])
            }else{
                console.log(key,obj[key]);    //如果不是对象就输出 健名 每一个属性值
            }
        }
    }
    showObjValue(obj);  //2.深遍历 遍历每一个值

11.2递归小案例

 例:1.普通写法
    var i=0;
    var sum=0;
    function getSum(){
        i++;
        sum+=i;
        if(i<10) getSum();
    }
    getSum();
    console.log(sum)

    2.递归 求和 0-10 的求和
    function getSum(i,sum){
        i++;
        sum+=i;
        if(i<10) return getSum(i,sum);
        return sum;
    }
      var s=  getSum(0,0);
        console.log(s);
        
    //解析 下面是不ruturn的结果  
    function getSum(i,sum){
        i++;
        sum+=i;
        if(i<10) sum=getSum(i,sum);
        return sum;
    }

      var s=  getSum(0,0);
        console.log(s);  // 1 原因如下 最后一句不执行时 一直向上返回 直到返回最顶部 return出来 所以结果为1
    

微信图片_20220606220807.png

11.3求对象的最大深度(必考)

 var obj = {
       a:1,
       b:{
           c:{
               d:{
                   e:{
                       f:{
                           g:{
                                // currentLv 7  maxLv 7
                           }
                       }
                   }
               }
           }
       },
       aa:{
           bb:{
               cc:{
                   dd:1 //currentLv 4  maxLv 7   //不是递归不 + 1
               }
           }
       }
    };
    
 //必须会 这段
 function getMaxLv(obj, currentLv, maxLv) {
        if (maxLv === undefined) maxLv = 1;    //最大深度没有时 默认1
        if (currentLv === undefined) currentLv = 1; //当前深度没有时 默认1
        if (maxLv < currentLv) maxLv = currentLv; //最大深度小于当前深度时 最大深度=当前深度
        for (var key in obj) {                   //循环遍历对象
            if (typeof obj[key] === "object") {  // typeof判断 如果有对象类型 继续下去遍历
              maxLv = getMaxLv(obj[key], currentLv + 1, maxLv); //依次往深处比较所以current+1
            }                                                   //每进入一次 current就要+1次
        }
        return maxLv;
    }
    
 var n = getMaxLv(obj);
 console.log(n) //7

11.3 对象深比较 面试(必考)

   对象深比较 只比较对象不比较数据类型  面试(必考)  
   准备:  bool小开关  Object.keys(o1).length获得属性的数量  depthCompare中文深入比较
    function depthCompare(o1,o2,bool){     
        if(bool===undefined) bool=true;
        if(Object.keys(o1).length!==Object.keys(o2).length) return bool=false; //键名长度都不一样直接返回
        for(var key in o1){         //键名数量相同时,比较这些键在另一个里有没有for循环
            if(typeof o1[key]==="object"){    //typeof判断 如果是对象的话 就继续深入
               bool=depthCompare(o1[key],o2[key],bool)
            }else{                           //如果不是对象 
                if(o1[key]!==o2[key]) return bool=false; //o1值不等于o2值就返回
            }
        }
        return bool
    }


    var obj={a:1,c:2,b:3,d:{e:10},f:{ss:11,dd:11}};
    var obj1={a:1,b:3,c:2,f:{dd:11,ss:11},d:{e:10}};

    var bool = depthCompare(obj,obj1);
    console.log(bool)