js-day05

129 阅读7分钟

函数

制作简易计算器
<input type="text" id="txt1">
    <!-- 注意点:option标记的value可以直接通过select的value直接获取,当你选中是那个option,获取到的就是那个option的值 -->
    <select id="sel">
        <option value="+">+</option>
        <option value="-">-</option>
        <option value="*">*</option>
        <option value="/">/</option>
    </select>
    <input type="text" id="txt2">
    <button id="btn">=</button>
    <input type="text" id="txt3">
    <button id="clear">clear</button>
    <script>
        // 封装选择器
        function $(id){
            return document.getElementById(id)
        }

        // 获取元素
        var txt1 = $('txt1')
        var txt2 = $('txt2')
        var txt3 = $('txt3')
        var sel = $('sel')
        var btn = $('btn')
        var clear = $('clear')

        // 绑定事件
        btn.onclick = function(){
            // 非空验证
            if(txt1.value == '' || txt2.value == ''){
                alert('亲,内容不能为空?')
                return
            }
            var num1 = Number(txt1.value)
            var num2 = Number(txt2.value)
    
            // 根据输入符号进行匹配
            switch(sel.value){
                case '+':
                    txt3.value =  num1 + num2
                    break
                case '-':
                    txt3.value =  num1 - num2
                    break
                case '*':
                    txt3.value =  num1 * num2
                    break
                case '/':
                    txt3.value =  num1 / num2
                    break
            }
        }

        // 清空文本框的值
        clear.onclick = function(){
            txt1.value = ''
            txt2.value = ''
            txt3.value = ''
        }
    </script>

作用域

指的是访问数据时的规则(区域、范围)

分类

  • 全局作用域,整个script标记内部都属于全局作用域
  • 局部作用域,指的是函数内部

变量分类

  • 全局变量,声明全局作用域里面的变量,称之为全局变量(声明在函数外部)
  • 局部变量,声明在函数内部的变量,称之为局部变量

访问数据规则

  • 外部不能访问函数内部的变量
  • 函数内部可以访问函数外部的变量

注意:在函数内部声明的变量,如果没有使用var关键字的话那么它就属于全局变量

js设计缺陷
  • 要求声明变量时必须使用var关键字,但是在实际的使用过程中你不使用其实变量也可以声明
function fn(){
            // 要求在函数内部声明的变量属于局部作用域,结果呢?就是由于没有使用var关键字,既然在函数外部可以使用
            b = 30
        }
        fn()
        console.log(b)
  • 在函数内部不使用var,局部变量会变成全局变量
  • 关于name问题:name不是关键字,但是你使用后,会出现一些其他的情况

问题1:使用name声明变量,注释后去打印结果依旧存在

       var name = '张三'
       console.log(name)
       var a = '张三'
       console.log(a)

问题2:当你使用name给它赋值为引用数据类型时,不会按照数据类型规则去解析(因为你给name赋值的所有数据类型它都会转成字符串类型)

var name = function(){
     onsole.log('你好!')
 }
 console.log(name)  
 name() // name is not a function
var name = 10
console.log(window)

作用域链

  • 作用域链把作用域详细进行了划分,把全局作用域称之为0级作用
  • 把函数内部划分为1级、2级、3级等等作用域(函数嵌套函数的情况下,以函数的嵌套关系划分)
  • 把这些作用域连接起来形成一个类似于链条的关系,把这种情况称之为作用域

访问规则:

  • 先在当前的作用域里面进行查找
  • 如果找到就使用,如果没有找到就去上一级作用域里面进行查找,直到找到0级还是没有就报错了

变量的生命周期

指的是变量从声明到销毁的过程

全局变量: 当网页关闭后才销毁

局部变量: 当函数执行完毕就销毁

预解析

浏览器不会直接按照你写代码的顺序直接去解析代码,需要先把代码加工处理后再去逐行解析代码,把这个加工处理代码的过程称之为预解析

步骤:

  1. 先把变量声明和函数声明提升到当前作用域的最顶端
  2. 再根据原先代码的书写顺序逐行执行代码

注意:

  • 变量声明指的是 var 变量名称
  • 函数声明指的是整个函数体,不包括函数调用 function fn(){}
函数两种声明方式

1.直接声明

function fn(){
            console.log('hello')
        }
   fn()

2.表达式声明

var fn = function(){
            console.log('hello')
        }

如果把函数赋值给一个变量,那么函数不会进行变量声明提升

fn() // fn is not a function
var fn = function(){
     console.log(123)
}

递归函数

  • 递归指的是函数自己调用
  • 要求递归必须有出口:如果没有结束条件,那么就变成了一个死循环
  • 注意点递归是比较好用的,但是得发现规律才行
        var i = 0
        function buddhistMonk(){
            i++
            console.log(i+'老和尚讲故事,从前有座山,山里有座庙,庙里有个老和尚,老和尚对小和尚说,从前有座山,山里有座庙,庙里有个老和尚...')
            if(i<100){
                buddhistMonk()
            }
        }
        buddhistMonk()
递归练习
  • 1+2+3+....+100的和?
        function getSum(n){
            // 第一次进来 5==1 不满足条件,执行下面的代码
            // 第二次进来 4==1 不满足条件,执行下面的代码
            // 第三次进来 3==1 不满足条件,执行下面的代码
            // 第四次进来 2==1 不满足条件,执行下面的代码
            // 第五次进来 1==1 满足条件,进入判断体里面,把1直接返回
            if(n==1){
                return 1
            }
            /*
                  5 + getSum(4) 把这个返回给外界
                  5 + 4 + getSum(3) 把这个返回给外界
                  5 + 4 + 3 + getSum(2) 把这个返回给外界
                  5 + 4 + 3 + 2 + getSum(1) 把这个返回给外界
            */ 
            return n + getSum(n-1)
        }
        // 第一次接收到的结果 5 + getSum(4)  把之前返回的结果保存在内存里面的
        // 第二次接收到的结果 5 + 4 + getSum(3) 把之前返回的结果保存在内存里面的
        // 第三次接收到的结果 5 + 4 + 3 + getSum(2) 把之前返回的结果保存在内存里面的
        // 第四次接收到的结果 5 + 4 + 3 + 2 + getSum(1) 把之前返回的结果保存在内存里面的
        // 第五次接收到的结果 5 + 4 + 3 + 2 + 1 = 15
        getSum(5)
  • 斐波那契数列:1、1、2、3、5、8、13、21、34……

规律:这个数列从第3项开始,每一项都等于前两项之和

分析:fb(n) = fb(n-1) + fb(n-2)

 function fb(n){
            if(n==1 || n==2){
                return 1
            }
            return fb(n-1) + fb(n-2)
        }
 fb(5)

array数组

就是一组数据的集合,说明数组里面可以存储很多的数据

声明方式:

  • []字面量方式
        var arr = ['张三', '王成']
        console.log(arr)
  • new Array() 构造函数方式,是创建对象的一种方法(构造函数也是函数,只不过它的功能更为强大,可以直接创建对象)
var arr = new Array('张三', '王成', '王成女朋友')
console.log(arr.length)

注意: 构造函数方式创建的数组,如果给里面传递一个(只有一个数组元素)数值类型的数据,那么它会表示限定数组长度为多少

        var arr = new Array(10)
        console.log(arr)

数组下标 :

  • 名称:下标、索引(index)
  • 在创建数组的时候,默认会给每一个数组成员(元素)添加一个编号,用于区分不同的数组元素,把这个编号称之为下标
  • 数组的下标默认是从0开始的
  • 数组下标作用:可以用来获取数组元素、删除、增加、替换等等
        var arrAge = [18, 20, 24, 19, 23]
        console.log(arrAge[0])
        console.log(arrAge[1])

数组属性:length 表示数组长度

        // 遍历数组
        for(var i=0; i<arrAge.length; i++){
            console.log(arrAge[i])
        }
伪(类)数组(arguments对象)

不是真正的数组,但是可以使用数组的属性和方法,把这种数组称之为伪数组

arguments对象

作用:

  • 用来保存实参里面的数据
  • 当实参或者形参的个数不确定的情况下使用
  arguments.length 表示实参的个数
  arguments.callee.length 表示形参的个数
  arguments.callee() 表示的是当前函数的名称
function getSum(){
    var sum = 0
    for(var i=0; i<arguments.length; i++){
        sum += arguments[i]
    }
    return sum
}
var res = getSum(10, 20, 30, 60, 80)
console.log(res)
 function fn(a, b, c){
     // console.log(arguments.callee.length)
     // console.log(arguments.length)
     if(arguments.length > 3){
         alert('亲,实参只能传递三个哦!')
     }
 }   
 fn(10, 20, 30)