JS基础--数组的应用&函数&作用域

141 阅读2分钟

一、数组的应用

1.1-根据数组元素生成手风琴
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box{
            width: 1120px;
            height: 260px;
            margin: 50px auto;
            display: flex;
            overflow: hidden;
        }

        .box>div{
            width: 120px;
            border: 1px solid #fff;
            transition: all 0.5s;
        }

        .box>div:hover{
            width: 400px;
        }
    </style>
</head>
<body>
    <!-- <div class="box">
        <div><img src="./images/1.jpg" alt=""></div>
        <div><img src="./images/2.jpg" alt=""></div>
        <div><img src="./images/3.jpg" alt=""></div>
        <div><img src="./images/4.jpg" alt=""></div>
        <div><img src="./images/5.jpg" alt=""></div>
        <div><img src="./images/6.jpg" alt=""></div>
        <div><img src="./images/7.jpg" alt=""></div>
    </div> -->

    <script>
        // 模拟后台返回的数据
        let arr = [
            './images/1.jpg',
            './images/2.jpg',
            './images/3.jpg',
            './images/4.jpg',
            './images/5.jpg',
            './images/6.jpg',
            './images/7.jpg',
        ]

        let str = '<div class="box">';
        for(let i = 0; i < arr.length; i++){
            str += `<div><img src="${arr[i]}" alt=""></div>`
        }
        str += '</div>'
        document.write(str);
    </script>
</body>
</html>

手风琴.png

1.2-根据数组元素生成柱状图
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      .box {
        width: 1000px;
        height: 400px;
        border-left: 1px solid #000;
        border-bottom: 1px solid #000;
        margin: 50px auto;
        /* 父元素伸缩盒子 */
        display: flex;
        /* 水平方向均匀分布 */
        justify-content: space-around;
        /* 垂直方向底部对齐 */
        align-items: flex-end;
      }

      .box > div {
        width: 50px;
        height: 100px;
        background-color: pink;
        text-align: center;
        font-size: 14px;
        /* 伸缩盒子 */
        display: flex;
        /* 修改伸缩盒子主轴为垂直方向 */
        flex-direction: column;
        /* 修改主轴方向两端对齐 */
        justify-content: space-between;
      }

      .box > div span {
        margin-top: -20px;
      }

      .box > div h3 {
        margin-bottom: -40px;
      }
    </style>
  </head>
  <body>
    
    <!-- <div class="box">
      <div>
        <span>50</span>
        <h3>一季度</h3>
      </div>
      <div>
        <span>50</span>
        <h3>二季度</h3>
      </div>
      <div>
        <span>50</span>
        <h3>三季度</h3>
      </div>
      <div>
        <span>50</span>
        <h3>四季度</h3>
      </div>
      <div>
        <span>50</span>
        <h3>一季度</h3>
      </div>
    </div> -->
    <script>
        // 定义一个数组模拟后台返回的数据
        //          
        let month = [100, 120, 230, 110, 300, 260, 130, 90, 300, 200, 150, 80];
        let strHtml = '<div class="box">';
        for(let i = 0; i < month.length; i++){
          strHtml += `<div style="height: ${month[i]}px;">
              <span>${month[i]}</span>
              <h3>${i+1}月</h3>
            </div>`
        }
        strHtml += '</div>'
        document.write(strHtml);
    </script>
  </body>
</html>

柱形图.png

1.3 求数组中的最大值
/* 
        擂台思想:
            1. 先定义一个变量 max 将数组中的0号元素赋值给max
            2. 从1号下标开始遍历数组
            3. 将遍历 到的元素 与 max里的值进行比较
            4. 如果 遍历到的元素 比 max里的大,就覆盖max里的值
        */

        /* let arr = [20, 30, 8, 40, 12, 24, 15];
        // 1. 先定义一个变量 max 将数组中的0号元素赋值给max
        let max = arr[0]

        // 2. 从1号下标开始遍历数组
        for(let i=1; i<arr.length; i++){
            // 3. 将遍历 到的元素 与 max里的值进行比较
            if(arr[i] > max){
                // 4. 如果 遍历到的元素 比 max里的大,就覆盖max里的值
                max = arr[i]

            }
        }

        console.log(max) */
1.4 数组的冒泡排序法
<script>
    let arr = [9, 5, 3, 8, 17, 6];
    // 外层循环控制找几次最大的
    for(let j = 1; j < arr.length; j++){
      // 内层:最大的放在最后面
      // i 与 i+1 相邻的两个数比较
      for(let i = 0; i < arr.length -j; i++){
        // 如果前面的比后面的大,就交换位置
        if (arr[i] > arr[i+1]){
          let c = arr[i];
          arr[i] = arr[i+1];
          arr[i+1] = c;
        }
      }
    }
    console.log(arr);
  </script>

二、函数类型

1.0-函数介绍
  • 1.在实际开发中,我们有很多功能代码 并不是只执行一次,而是需要在很多个地方

    • 例如我们之前学习过的求和功能 :购物车页面需要求和,自己的订单列表页面需要求和查看总消费,还有待付款页面等等
    • 多个地方:可以是同一个程序员好多个页面都需要使用。 也可以是不同程序员所负责的页面
  • 2.那么既然是相同的功能代码,我们肯定不能复制粘贴去写冗余代码。这样万一功能有变化,维护起来就会很不方便

  • 3.而函数就是解决这些重复功能的 代码复用问题

    • 函数是一个数据类型,可以理解为存储代码的容器。 把这些代码给存到变量中,要使用的时候取出来执行即可。
1.1-函数声明/调用
/* 需求:一段代码 需要在很多个地方使用 */

      /*函数语法 
        
        1.声明函数 : 是一个存储过程,此时不会执行函数体代码  
            function 函数名(){
                函数体代码: 需要存储的一段代码
            }

        2.调用函数 : 执行函数体代码
            函数名()
      */
function nxn(){
    let str = '<table width="800" height="500" border="1" rules="all">';
    for(let col=1;col<5;col++){     
        str += '<tr>';
        for(let row=1;row<= col;row++){   
             str += `<td>${row}*${col}=${row * col}</td>`; 
        } 
        str += '</tr>';
     }
     str += '</table>';
     document.write(str)
}
// 函数的调用
// 函数定义的代码不会自动执行,必须人为的调用
// 语法:函数名()
//调用者A
nxn();
//调用者B
nxn();
1.2-函数参数
  • 函数参数 : 调用者 传递数据 函数
    1. 传:调用者 ----函数名(实际参数)
    2. 收:函数 ----function 函数名(形式参数){ //函数体代码 }
    3. 函数传参本质: 实参给形参赋值的过程
      1. 函数传参是按照传入顺序一一赋值
      2. 函数每一次调用传参过程都是独立的,互不影响
      3. 函数 形参数量 和 实参数量 可以不一致的
<script>
    /* 
    参数的作用是用于在调用函数是向函数内部传递数据
    参数分形参与实参。
        形参:
            函数定义时的参数,
            在函数内部就是一个变量

        实参:
            函数调用时的参数
        
        实参与形参之间就是一个是传递一个是接收
    */

     function getSum(v1,v2){
         console.log(v1,v2)
     }
     let x = 10;
     getSum(x,200);           // 对10 与20 求和

     getSum(30,50);           // 对30 与50 求和
     /*
     形参 与 实参,共用作用将外部的数据传递到函数内部。
     实参是传,形参是收
     数据的传递是按顺序
     形参只在内部有效
     函数的参数就是将函数外部数据传递到函数内部进行运算。
     */
1.3 函数的参数细节
<script>
        function fn(x,y,z,arr){
            // console.log(x,y,z);
            console.log(arr);
        }

        let a = 10;
        fn(a, true, 'hello', [40,50,60,70])     // let arr =  [40,50,60,70]

        // console.log(x);     // 尝试在函数外部访问形参,报错

        /* 
        细节:
            实参与形参之间是按顺序传递,
            形参就是一个变量,只在函数内部访问
            参数可以是任何类型
        */
</script>
1.4 函数形参实参个数匹配
<script>
    // 函数形参实参个数匹配
    function getSum(num1, num2) {
        console.log(num1 + num2);
    }
    // 1. 如果实参的个数和形参的个数一致 则正常输出结果
    getSum(1, 2);
    // 2. 如果实参的个数多于形参的个数 会取到形参的个数
    getSum(1, 2, 3);
    // 3. 如果实参的个数小于形参的个数 多于的形参定义为undefined  最终的结果就是NaN
    // 形参可以看做是不用声明的变量  num2 是一个变量但是没有接受值  结果就是undefined  在JavaScript种,形参的默认值是undefined。
    getSum(1); // NaN
    // 建议 我们尽量让实参的个数和形参相匹配
</script>
1.5 函数默认参数(逻辑短路运算)
<script>
      /* 
        1.函数默认参数,我们自己在开发中使用不多。(了解后面很多js框架函数默认参数底层原理)
        2.函数默认参数 使用 逻辑运算符短路运算(逻辑中断)
            2.1 短路运算: 左边式子就可以决定结果,右边式子不执行
                && : 一假则假
                || : 一真则真
                 ! : 取反(没有短路运算,因为只有一个式子)
            2.2 短路规则:
                && : 找假。  左边式子值可以转成false,则无条件返回左边式子的值,右边不执行。 反之无条件返回右边式子的值。
                || : 找真。 左边式子值可以转成true,则无条件返回左边式子的值,右边不执行。 反之无条件返回右边式子的值。 
        
        */

        let res = undefined && 20
        console.log( res )//undefined

        let res1 = undefined || 20
        console.log( res1 )//20
        
      //需求:给函数添加默认参数0
      // (1)如果用户有传递实参,就使用用户传递的实参
      // (2)如果没有传,就使用默认参数
      function getSum(num1,num2){
          num1 = num1 || 0
          num2 = num2 || 0
          console.log(num1+num2)
      }

      getSum(66)  
</script>
1.6 函数参数练习
/ 需求:封装一个函数,对任意数组求和       
        function getSum(data){
            // console.log(data);
            
            let sum = 0;
            for(let i=0;i<data.length;i++){
                sum += data[i] 
            }

            // 这里的输出仅仅是为了验证代码正确,所以能log
            console.log(sum)
        }

        let arr = [10,20,30,4];

        getSum(arr)

        getSum([4,2,7,4,10,29]) 
// 需求:封装一个函数,实例对任何一个数组求最大值。
        function getMax(arr){
            let max = arr[0]
            for(let i = 0; i < arr.length; i++){
                if(arr[i] > max){
                    max = arr[i];
                }
            }
            console.log(max);
        }

        getMax([10,21,8,17,59,45,37]);
1.7 函数的返回值
函数返回值 : 函数 传递数据 给调用者
            1. 传 : 函数
                function 函数名(){ return 值 }
            2. 收 :  调用者
                let 变量名 = 函数名()
            3. 注意点
                (1)函数return关键字后面的代码不会执行的
                    * 只要有return关键字,函数体立即结束执行。
                (2)如果函数没有return,则默认返回值是undefined
 // 函数的返回值
 // return 数据
 // 函数内部return的数据会返回到函数的调用处

   function fn(){
       // 定义一个变量模拟函数内部生成的数据
       let data = 200;
       // 函数内部的数据可以在内部访问
       console.log(data);
       // 将data中的数据返回
       return data;
   }

   // 外部要接收
   let ret = fn();
   console.log(ret)
1.8 return的特点
<script>
        // 1. 函数内部只要遇到return就会中断函数的执行
        // function fn(){
        //     console.log('hello')
        //     return 100;
        //     console.log('world')
        // }

        // fn();

        // 2. 函数内部如果想返回多个数据,需要将多个数据组成数组
        // function fn(){
        //     return [10, 20];
        // }

        // let ret = fn();
        // console.log(ret)


        // 3. 函数内部的return后可以不写数据,单纯只是为了中断函数的执行
        function fn(){
            // ....
            // ....
            // ....

                return;
 
            // ....
            // ....
            // ....
        }

        fn();

        // 4. 函数的参数可以是任何类型,函数的返回值也可以是任何类型
        
    </script>
1.9 arugments的使用

当我们不确定有多少个参数传递的时候,可以用arguments来获取,在JavaScript中,arguments实际上它是当前函数的一个内置对象。所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有实参。

arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:

  • 具有length属性
  • 按索引方式存储数据
  • 不具有数组的push,pop等方法
// arguments 的使用  只有函数才有arguments对象  而且是每个函数都内置好了这个arguments
function fn(){
	console.log(arguments); //里面存储了所有传递过来的实参
	console.log(arguments.length); // 3
	console.log(arguments[2]); //3
	// 我们可以按照数组的方式遍历arguments
	for(var i = 0; i < arguments.length; i++){
		console.log(arguments[i]);
	}
}
fn(1,2,3);
//伪数组 并不是真正意义上的数组
// 1.具有数组的length
// 2.按照索引的方式进行存储的
// 3.它没有真正数组的一些方法 pop()  push() 等等
1.10 函数返回值练习
// 封装一个函数,对任意数组求最大值,并将最大值返回。
        /* function getMax(data){      // data = arr

            let max = data[0];
            for(let i=1;i<data.length;i++){
                if(data[i] > max){
                    max = data[i]
                }
            }
            return max;

        }

        let arr = [5,20,19,28,23,17]
        let ret = getMax(arr)

        console.log(ret) */
<script>
     // 封装一个函数,
     // 功能:在一个数组中查找是否有某个元素存在,如果存则返回true,
     /**
      * @param1 array
      * @param2 *
      * @return boolean
       */
     function find(arr,target){      
         // let arr = ['zhangsan','lisi','wangwu','zhaoliu','tianqi']
         // let target = 'qq'
         for(let i=0;i<arr.length;i++){
             if(arr[i] == target){
                 return true;
             }
         }
     }

     let stus = ['zhangsan','lisi','wangwu','zhaoliu','tianqi'];
     let na = 'lisi'
     let ret = find(stus,na);
     console.log(ret);
</script>
1.11 利用函数求任意个数的最大值
<script>
	// 利用函数求任意个数的最大值
	function getMax(){ //arguments = [1,2,3]
		var max = arguments[0];
		for(var i = 1; i < arguments.length; i++) {
			if (arguments[i] > max) {
				max = arguments[i];
			}
		}
		return max;
	}
	console.log(getMax(1,2,3)); // 3
	console.log(getMax(1,2,3,4,5)); //5
	console.log(getMax(11,2,34,444,5,100)); //444
</script>
1.12 函数是可以相互调用的
<script>
	// 函数是可以相互调用的
	function fn1(){
		console.log(11);
		fn2();  // 在fn1 函数里面调用了 fn2 函数
	}
	fn1();
	
	function fn2() {
		console.log(22);
	}
</script>
1.13 利用函数判断闰年
<script>
	// 用户输入年份,输出当前年份2月的天数
	function backDay() {
        var year = prompt('请您输入年份:');
        if() { // 调用函数需要加小括号
            alert('当前年份是闰年2月份有29天');
        } else {
			alert('当前年份是平年2月份有28天');
        }
	}
	backDay();
	
	// 判断是否是闰年的函数
	function isRunYear(year) {
		// 如果是闰年我们返回 true  否则 返回false
		var flag = false;
		if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
			flag = true;
		}
		return flag;
	}
</script>
1.14 函数的两种声明方式
<script>
	// 函数的2种声明方式
	// 1.利用函数关键字自定义函数(命名函数)
	function fn() {
		console.log('我是函数')
	}
	fn();
	// 2.函数表达式(匿名函数)
	// var 变量名 = function() {};
	var fun = function(aru) {
		console.log('我是函数表达式'); // 我是函数表达式
		console.log(aru);  // hahaha
	}
	fun('hahaha');
	// (1) fun是变量名 不是函数名
	// (2) 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而 函数表达式里面存的是函数
	// (3) 函数表达式也可以进行传递参数
</script>
1.15 匿名函数
<script>
      // 具名函数,如下代码,函数的名称就是test
      // function test() {}
      // 函数名称() >> test()
      // 匿名函数不能单独存在,它只有三个使用方式
      // function (){} // 报错》》需要一个标识符
      // 1.做为一个变量的值,值的类型是一个函数 -- 函数表达式
      let age = 20
      let fn = function() {
        console.log(123)
      }
      fn()

      // 2.做为一个自调用函数==立即执行的函数
      ;(function() {
        console.log(123)
      })()

      // 3.将匿名函数做为函数的参数--回调函数
      let btn = document.querySelector('button') // 获取元素
      // 为btn这个元素添加一个事件监听器,添加一个单击事件的监听,当用户真的单击这个按钮的时候,调用你所传入的处理函数
      btn.addEventListener('click', function() {})

      let aaabbb123 = function() {
        console.log('abc')
      }
      console.log(window)
1.16 利用函数转换时间案例
  • 需求: 用户输入秒数,可以自动转换为时分秒
  • 分析:
  • ①: 用户输入总秒数
  • ②:计算时分秒(封装函数) 里面包含数字补0
  • ③:打印输出
  • 计算公式:计算时分秒
  • 小时: h = parseInt(总秒数 / 60 / 60 % 24)
  • 分钟: m = parseInt(总秒数 / 60 % 60 )
  • 秒数: s = parseInt(总秒数 % 60)
<script>
    function getTime(miao) {
      // 获取时
      let hour = parseInt(num / 3600);
      // console.log(hour);
      // 获取分
      let minute = parseInt(num % 3600 / 60);
      // console.log(minute);
      // 获取秒
      let second = num % 60;
      // console.log(second);
      return [hour, minute, second];
    }
    let num = +prompt('请输入秒数'); // 3700
    let time = getTime(num);
    console.log(time); // [1, 1, 40]
    document.write(`${num}秒的时间是${time[0]}${time[1]}${time[2]}秒`);
</script>

三、作用域

1.1-作用域介绍
  • 注意:如果一个变量在声明的时候没有使用关键字。 例如: num = 10,此时这个变量无论写在哪里都是全局变量。 (切忌:这是非常不规范的,千万不要这么写,否则以后代码可能会出现bug)
<script>
        js变量作用域: 变量可以使用的区域
            * 作用:避免变量污染(变量名相同导致代码冲突)
        // 在JS中作用域可以全为三种:
        // 全局: 在函数之外就是全局
        //      全局变量:在全局定义的变量就是全局变量

        // 局部:在函数内部就是局部
        //      局部变量:在局部定义的变量就是局部变量

        // 块级:只要语法中具有{}都是块级作用域

</script>
<script>
        // 全局变量
        let a = 10;
        function fn(){
            // 局部变量
            let b = 20;
        }
</script>
1.2 变量的访问范围
<script>
        // 全局变量:访问不受限制
        // 局部变量:局部变量只能在定义的函数内访问

        // 全局变量
        let a = 10;
        function fn(){
            // 局部变量
            let b = 20;

            // 尝试在局部访问全局变量a
            // console.log(a);

            // console.log(b);
        }

        fn();

        // 尝试在全局访问局部变量b
        console.log(b);     // 报名无法访问

        // console.log(a);

</script>
1.3 块级作用域-专题
<script>
        // 只要语法中具有{}都会形成一个块级作用域
        // 块级作用域只影响let声明的变量    
        // var 也是用于声明变量。
        
        // let a = 10;
        // var b = [10,20];
        // console.log(a,b);

        // var与let的区别,主要体现在块级作用域上
        // {
        //     var y = 20;
        //     let x = 10;
        // }

        // console.log(y);     // 20
        // console.log(x);     // 报错

        // console.log(n);
        // var n = 20;

        // let m = 10;
        // console.log(m);

        // let声明的变量必须先定义后使用

        // 不推荐直接为变量赋值的方式定义变量,推荐使用let
        age = 20;
        console.log(age);

        /* 
        小结:
            let声明受块级作用域限制
            var也是用于声明变量的,var声明的变量不受块级作用域限制。
        
        */
</script>
1.4 作用域链以及链式查找
<script>
        // 作用域链:由嵌套的作用域形成的一个链条。
        // 链式查找:当在某个作用域内使用一个变量时,如果这个变量不存在,由会向上一级作用域找
        // 作用域链: 默认情况下,代码处于全局作用域(0级链),当声明一个函数之后就会开辟一个局部作用域(1级),而函数里面又可以声明一个函数,又会形成新的作用域(2级),以此类推形成的结构称之为作用域链
        // 变量访问规则: 就近原则
            * 当你在一个作用域访问变量的之后,首先会看当前作用域有没有声明。如果有则访问。 没有则往上级作用域查找,有没有声明。有则访问,没有则继续往上。直到作用域最顶端0级,如果还没有找到。则程序报错  xxx is not defined

    </script>
    <script>
        // let a = 10
        function fn(){
            // let a = 100
            function fn1(){
                let a = 1000
                function fn2(){
                    
                    console.log(a); // 1000
                }
                fn2();
            }
            fn1()
        }
        fn();
    </script>