函数补充及对象

函数

函数的概念

  • 对于 js 来说,函数就是把任意一段代码放在一个 盒子 里面

  • 在我想要让这段代码执行的时候,直接执行这个 盒子 里面的代码就行

  • 先看一段代码

    // 这个是我们以前写的一段代码
    for (var i = 0; i < 10; i++) {
      console.log(i)
    }
    ​
    // 函数,这个 {} 就是那个 “盒子”
    function fn() {
      // 这个函数我们以前写的代码
      for (var i = 0; i < 10; i++) {
        console.log(i)
      }
    }       //函数分为两种
            // 系统函数 比如 prompt()  alert()  
            // 自定义函数  当系统函数不满足我们的需求 我们可以自己定义函数

函数的两个阶段(重点)

  • 按照我们刚才的说法,两个阶段就是 放在盒子里面让盒子里面的代码执行

  • 内存分为栈内存和堆内存

    栈内存 基本数据类型 函数名在 栈内存

    堆内存 复杂数据类型 引用数据类型 函数体 在堆内存

函数定义阶段

  • 定义阶段就是我们把代码 放在盒子里面

  • 我们就要学习怎么 放进去,也就是书写一个函数

  • 我们有两种定义方式 声明式赋值式

    1-1 现在堆内存中开辟空间

    1-2 把函数体内的代码 原样复制到空间内(我们写代码写在硬盘上)

    1-3 把内存的地址 赋值给栈内存的函数名

    // 变量的定义
            // 定义在哪个作用域下 这个变量就是哪个作用域的私有变量 
            // 只能在这个作用域下或者这个作用域的子级作用域内使用 
            // 不能在父级作用域使用  = > 
            var n1 = 100;
            function fn1(){
                var n2 = 200; // n2是fn1的私有变量 只能在fn1下 或者fn1的子级下面使用
                console.log(n2);
                console.log(n1);
            }
            fn1()
            // console.log(n2);
            
             //变量的访问 
            // 首先在自己的作用域查找  如果有 那么直接使用 
            // 如果没有自动到父作用域查找 父作用域有 那么就使用
            // 如果还没有 再往上一级 直到全局作用域 发现还没有 那么 报错
            // xx is not defined 
             var n = 100;
            function fn2(){
                var n = 200;
                function fn3(){
                     var n = 300;
                    console.log(n);
                }
                fn3();
            }
            //fn2()
            //fn3()
            fn2()
            
             // 变量的赋值
            // 先在自己的作用域内部查找 如果有直接赋值 
            // 如果没有自动到父作用域查找 父作用域有 那么就使用 停止查找
            // 父作用域如果没有再往上到父级 直到 全局作用域  
            // 那么就把这个变量定义为全局变量 再进行赋值 
            var n = 100;
            function fn1(){
                var n = 200;
                console.log('前',n);
                n = 500
                console.log('后',n);
            }
            console.log('全局',n);
            fn1()
            console.log('全局后',n);

声明式

  • 使用 function 这个关键字来声明一个函数

  • 语法:

<script>  //声明式
        function story(){
            document.write('一言之美,贵于千金.——葛洪')
            document.write('人无忠信,不可立于世.——程颐')
            document.write('诚信为⼈之本。——鲁迅')
            document.write('⾔必信,⾏必果。——⼦路')
        }// function: 声明函数的关键字,表示接下来是一个函数了
// story: 函数的名字,我们自己定义的(遵循变量名的命名规则和命名规范)
// (): 必须写,是用来放参数的位置(一会我们再聊)
// {}: 就是我们用来放一段代码的位置(也就是我们刚才说的 “盒子”)
    </script>

赋值式

  • 其实就是和我们使用 var 关键字是一个道理了

  • 首先使用 var 定义一个变量,把一个函数当作值直接赋值给这个变量就可以了

  • 语法:

<script>  //赋值式
         var storle=function(){
            document.write('不信不⽴,不诚不⾏。——晁说之')
            document.write('读书贵精不贵多。——书摘')
            document.write('真诚是⼀种⼼灵的开放。——拉罗什富科')
            document.write('腹有诗书⽓⾃华,读书万卷始通神。——苏轼')
        }// 不需要在 function 后面书写函数的名字了,因为在前面已经有了
    </script>

函数调用阶段

  • 就是让 盒子里面 的代码执行一下

  • 让函数执行

  • 两种定义函数的方式不同,但是调用函数的方式都以一样的

2-1 按照函数名存的地址去找到对应的函数体

先判断栈内存中是否有这个变量

如果存在 也会判断里边是否存储的还一个函数体

2-2 在调用栈 内开辟一个新的 函数执行空间 (一个函数可以被多次调用为了避免一个调用出现的结果影响所有的调用

所以每次的调用都会申请一个执行空间)

2-3 在执行空间内 给形参赋值

2-4 在执行空间内 对函数体内的代码进行预解析

2-5 在执行空间内 对函数体内的代码 执行一遍

2-6 完成以后 这个执行空间被销毁 或者理解为空间被收回

调用一个函数

  • 函数调用就是直接写 函数名() 就可以了

    // 声明式函数
    function fn() {
      console.log('我是 fn 函数')
    }
    // 调用函数
    fn()
    ​
    // 赋值式函数
    var fn2 = function () {
      console.log('我是 fn2 函数')
    }
    // 调用函数
    fn()
    • 注意: 定义完一个函数以后,如果没有函数调用,那么写在 {} 里面的代码没有意义,只有调用以后才会执行

调用上的区别

  • 虽然两种定义方式的调用都是一样的,但是还是有一些区别的

  • 声明式函数: 调用可以在 定义之前或者定义之后

  • // 可以调用
    fn()
    // 声明式函数
    function fn() {
      console.log('我是 fn 函数')
    }
    // 可以调用
    fn()
  • 赋值式函数: 调用只能在 定义之后

    // 会报错
    fn()
    // 赋值式函数
    var fn = function () {
      console.log('我是 fn 函数')
    }
    // 可以调用
    fn()

函数的参数(重点)

  • 我们在定义函数和调用函数的时候都出现过 ()

  • 现在我们就来说一下这个 () 的作用

  • 就是用来放参数的位置

  • 参数分为两种 行参实参

    // 声明式
    function fn(行参写在这里) {
      // 一段代码
    }
    fn(实参写在这里)
    ​
    // 赋值式函数
    var fn = function (行参写在这里) {
      // 一段代码
    }
    fn(实参写在这里)

行参和实参的作用

  1. 行参

    • 就是在函数内部可以使用的变量,在函数外部不能使用

    • 每写一个单词,就相当于在函数内部定义了一个可以使用的变量(遵循变量名的命名规则和命名规范)

    • 多个单词之间以 , 分隔

      // 书写一个参数
      function fn(num) {
        // 在函数内部就可以使用 num 这个变量
      }
      ​
      // 书写两个参数
      function fun(num1, num2) {
        // 在函数内部就可以使用 num1 和 num2 这两个变量
      }
    • 如果只有行参的话,那么在函数内部使用的值个变量是没有值的,也就是 undefined

    • 行参的值是在函数调用的时候由实参决定的

  2. 实参

    • 在函数调用的时候给行参赋值的

    • 也就是说,在调用的时候是给一个实际的内容的

      function fn(num) {
        // 函数内部可以使用 num 
      }
      ​
      // 这个函数的本次调用,书写的实参是 100
      // 那么本次调用的时候函数内部的 num 就是 100
      fn(100) 
      // 这个函数的本次调用,书写的实参是 200
      // 那么本次调用的时候函数内部的 num 就是 200
      fn(200)
    • 函数内部的行参的值,由函数调用的时候传递的实参决定

    • 多个参数的时候,是按照顺序一一对应的

      function fn(num1, num2) {
        // 函数内部可以使用 num1 和 num2
      }
      // 函数本次调用的时候,书写的参数是 100 和 200
      // 那么本次调用的时候,函数内部的 num1 就是 100,num2 就是 200
      fn(100, 200)

参数个数的关系

  1. 行参比实参少

  • 因为是按照顺序一一对应的

  • 行参少就会拿不到实参给的值,所以在函数内部就没有办法用到这个值

  1. 行参比实参多

  • 因为是按照顺序一一对应的

  • 所以多出来的行参就是没有值的,就是 undefined

函数的return(重点)

  • return 返回的意思,其实就是给函数一个 返回值终断函数

终断函数

  • 当我开始执行函数以后,函数内部的代码就会从上到下的依次执行

  • 必须要等到函数内的代码执行完毕

  • return 关键字就是可以在函数中间的位置停掉,让后面的代码不在继续执行

返回值

  • 函数调用本身也是一个表达式,表达式就应该有一个值出现

  • 现在的函数执行完毕之后,是不会有结果出现的

  • return 关键字就是可以给函数执行完毕一个结果

    function fn() {
      // 执行代码
      return 100
    }
    // 此时,fn() 这个表达式执行完毕之后就有结果出现了
    console.log(fn()) // 100
  • 我们可以在函数内部使用 return 关键把任何内容当作这个函数运行后的结果

预解析

  • 在代码执行之前 对代码进行通读并且解释

  • 只解析两部分内容

    1. var 声明的变量名; => 仅仅是对var 声明的变量提前声明 暂时不赋值

    2. 声明式的函数

      => 对函数名字提前声明 并且直接给这个函数名赋值了 一个函数

      => 赋值式的函数按照 var变量的规则进行 解释

      会经历两个环节 解释代码执行代码

      注意点: 打开浏览器 只会解析全局代码 不对函数内的代码进行预解析 函数内的代码 仅仅会在函数调用的时候才会 预解析

    <script>
            function fn(){
                var num = 100;
                console.log(num)
            }
            // 如果仅仅写了上面代码 没有调用 也会预解析 
            // 声明变量 并且将 函数赋值给它  这时候不解析函数内部 
            // fn()   
            // 当调用的时候才解析函数内容不 
    ​
            // 预解析  
            // 直接声明一个fn的变量 并且将一个函数赋值给它
        
            //代码执行  
            // fn() 
            // 函数内部 预解析 
             // 解析var 变量 仅仅声明 没有赋值
             // 函数内部执行 
             // num = 100 
             //  输出到控制台
        </script>
    • 看下面一段代码

      fn()
      console.log(num)
      ​
      function fn() {
        console.log('我是 fn 函数')
      }
      ​
      var num = 100
    • 经过预解析之后可以变形为

      function fn() {
        console.log('我是 fn 函数')
      }
      var num
      ​
      fn()
      console.log(num)
      num = 100

作用域

变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域

全局作用域

  • 全局作用域是最大的作用域

  • 在全局作用域中定义的变量可以在任何地方使用

  • 页面打开的时候,浏览器会自动给我们生成一个全局作用域 window

  • 这个作用域会一直存在,直到页面关闭就销毁了

    /全局作用域
            // 一个html 页面打开这就是一个全局作用域
            // => window (了解)
            // 私有作用域  局部作用域 
        // 只有函数才有 if  while do while   for 他们都没有局部作用域 
            // 作用域的上下级关系 
            // 定义在哪个作用域内的函数 就是哪个作用域的子级作用域 
    // 下面两个变量都是存在在全局作用域下面的,都是可以在任意地方使用的
    var num = 100 // 私人可以使用公家的东西 
    var num2 = 200 // 公家不能随便使用私人的东西  

局部作用域

  • 局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域

  • 在局部作用域中定义的变量只能在这个局部作用域内部使用

  • JS 中只有函数能生成一个局部作用域,别的都不行

  • 每一个函数,都是一个局部作用域

    // 这个 num 是一个全局作用域下的变量 在任何地方都可以使用
    var num = 100
    function fn() {
      // 下面这个变量就是一个 fn 局部作用域内部的变量
      // 只能在 fn 函数内部使用
      var num2 = 200
    }
    fn()

变量使用规则(重点)

  • 有了作用域以后,变量就有了使用范围,也就有了使用规则

  • 变量使用规则分为两种,访问规则赋值规则

变量的定义

//定义在哪个作用域下 这个变量就是哪个作用域的私有变量 
        // 只能在这个作用域下或者这个作用域的子级作用域内使用 
        // 不能在父级作用域使用  = > 
        var n1 = 100;
        function fn1(){
            var n2 = 200; // n2是fn1的私有变量 只能在fn1下 或者fn1的子级下面使用
            console.log(n2);
            console.log(n1);
        }
        fn1()
        // console.log(n2);

访问规则

  • 当我想获取一个变量的值的时候,我们管这个行为叫做 访问

  • 获取变量的规则:

    • 首先,在自己的作用域内部查找,如果有,就直接拿来使用

    • 如果没有,就去上一级作用域查找,如果有,就拿来使用

    • 如果没有,就继续去上一级作用域查找,依次类推

    • 如果一直到全局作用域都没有这个变量,那么就会直接报错(该变量 is not defined)

    var num = 100
    function fn() {
      var num2 = 200
      function fun() {
        var num3 = 300
        console.log(num3) // 自己作用域内有,拿过来用
        console.log(num2) // 自己作用域内没有,就去上一级,就是 fn 的作用域里面找,发现有,拿过来用
        console.log(num) // 自己这没有,去上一级 fn 那里也没有,再上一级到全局作用域,发现有,直接用
        console.log(a) // 自己没有,一级一级找上去到全局都没有,就会报错
      }
      fun()
    }
    fn()
    ​
     var n = 100;
            function fn2(){
                var n = 200;
                function fn3(){
                     var n = 300;
                    console.log(n);
                }
                fn3();
            }
            //fn2()
            //fn3()
            fn2()
  • 变量的访问规则 也叫做 作用域的查找机制

  • 作用域的查找机制只能是向上找,不能向下找

    function fn() {
      var num = 100
    }
    fn()
    console.log(num) // 发现自己作用域没有,自己就是全局作用域,没有再上一级了,直接报错

赋值规则

  • 当你想给一个变量赋值的时候,那么就先要找到这个变量,在给他赋值

  • 变量赋值规则:

    • 先在自己作用域内部查找,有就直接赋值

    • 没有就去上一级作用域内部查找,有就直接赋值

    • 还没有再去上一级作用域查找,有就直接赋值

    • 如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,再给他赋值

    function fn() {
      num = 100
    }
    fn()
    // fn 调用以后,要给 num 赋值
    // 查看自己的作用域内部没有 num 变量
    // 就会向上一级查找
    // 上一级就是全局作用域,发现依旧没有
    // 那么就会把 num 定义为全局的变量,并为其赋值
    // 所以 fn() 以后,全局就有了一个变量叫做 num 并且值是 100
    console.log(num) // 100
    ​
     var n = 100;
            function fn1(){
                var n = 200;
                console.log('前',n);
                n = 500
                console.log('后',n);
            }
            console.log('全局',n); //100
            fn1()
            console.log('全局后',n);//100

递归函数

  • 在编程世界里面,递归就是一个自己调用自己的手段

  • 递归函数: 一个函数内部,调用了自己,循环往复

  • // 下面这个代码就是一个最简单的递归函数
    // 在函数内部调用了自己,函数一执行,就调用自己一次,在调用再执行,循环往复,没有止尽
    function fn() {
      fn()
    }
    fn()
  • 其实递归函数和循环很类似

  • 需要有初始化,自增,执行代码,条件判断的,不然就是一个没有尽头的递归函数,我们叫做 死递归

  • 递归也是有限制的 不能无限的调用自己 注意:调用的次数

<script>//.求斐波那契数列列中第n个数的值:1,1,2,3,5,8,13,21,34....   前两个相加
        function feibo(n){
            var a=1
            var b=1
            var c=0
            if(n<=2){
                return 1
            }else{
                while(n>2){
                    c=a+b
                    a=b
                    b=c
                    n--  
                }
                return c
            }
        }
        document.write(feibo(6))
    </script>
<script> //递归版  
        function age(num){
            if(num<=2)return 1
            return age(num-1)+age(num-2)
        }
        document.write(age(6))
    </script>

对象

  • 对象是一个复杂数据类型 万物皆对象

  • 其实说是复杂,但是没有很复杂,只不过是存储了一些基本数据类型的一个集合

    var obj = {
      num: 100,
      str: 'hello world',
      boo: true
    }
  • 这里的 {} 和函数中的 {} 不一样

  • 函数里面的是写代码的,而对象里面是写一些数据的

  • 对象就是一个键值对的集合

  • {} 里面的每一个键都是一个成员

  • 也就是说,我们可以把一些数据放在一个对象里面,那么他们就互不干扰了

创建一个对象

  • 字面量的方式创建一个对象

    var wangzhen = {
                'username':'wangzhen',
                'age':18,
                goodman:true,
                singing:function(){
                    console.log('窗外的麻雀在电线杆上撒粮');
                },
                love:function(){
                    console.log('过了这个村我在下个村等你')
                }
            }
            wangzhen.sex = 1;
            alert(wangzhen.sex)
            // alert(typeof wangzhen) // object
            alert(wangzhen.username) // 查看静态属性不用加()
            wangzhen.love() // 调用动态方法 需要加()
            // 使用内置的工具(函数)来创建对象
  • 内置构造函数的方式创建对象

     var yinghao = new Object();
            yinghao.name = 'ahao';
            yinghao.age = 1;
            yinghao.eating = function(){
                console.log('正在吃')
            }
    • Objectjs 内置给我们的构造函数,用于创建一个对象使用的

建议使用第一种来创建对象

键的名字按照变量的命名规则 规范

不要有重复 后边 会覆盖前面

可以使用纯数字 作为键名 自动把数字排到最前面

也可以使用特殊符号作为键名

键的 可加单引号 可不加单引号 但是如果用特殊符号作为键名 必须加单引号

建议使用字符串作为键名

  var jianzeng = {
            name:'jiangjiang',
            age:18,
            ball:function(){
                return '千锋白巧克力'
            }
        }
        // 增
        // jianzeng.height = '181cm';
        // alert(jianzeng.height)
         减  delete 
        // alert(jianzeng.age);
        // delete jianzeng.age;
        // alert(jianzeng.age);
        // 改 
        //重新赋值就是改的过程 
        // alert(jianzeng.name);
        // jianzeng.name = 'xiaojiang'
        // // alert(jianzeng.name);
        // //查 
        // alert(jianzeng.age) // 查看静态属性
        // alert(jianzeng.ball())//调用动态方法
  当对象的键名字中有 纯数字 特殊符号 
  这个时候 增删改查 要使用 中括号的方式巧用

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340