• 函数的声明与作用域


    函数的声明与作用域

    全文总计7500字,代码和符号约为3000字符,正文约4030字,预计阅读约20分钟

    扩展阅读JS基础函数的参数

    声明操作

    旧版本(ES6之前):var function

    var:通用的,可以省民变量,储存任意类型的值

    var a=1,b=true.....
    
    • 1

    function:只能晟敏函数,声明一个变量来存储函数

    function c(){
          
    }
    
    • 1
    • 2
    • 3

    作用域:具有一个特殊作用的对象类型
    在JS里面万物皆为对象

    全局作用域

    全局作用域 用于存储系统API【接口】

    JS的宿主环境

    宿主与寄生:寄生虫-寄生在什么物体上,这个物体就是宿主

    JS运行在什么环境中,这个环境就叫宿主
    比如:JS运行在浏览器上浏览器就是宿主
    JS就能使用浏览器的各种功能

      console.log(window)
    
    
    • 1
    • 2

    如下图
    在这里插入图片描述
    这是什么数据类型呢?
    在这里插入图片描述
    我们可以看到,他是个对象的类型所以我们可以调用他来是先
    比如 alert是浏览器提供的最基础的弹窗组件

    例如:

    <script>
        window.alert("hello world!");
    script>
    
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    所以:凡是存在window中的–称为全局对象或全局作用域

    由于window是专门存储API的对象,所以也成为 作用域

    在全局作用域里面,前面的(window.)可以省略

    全局污染

    全局污染:是用来存放系统API的如果把我们自己定义的属性放在全局作用域中,就叫全局污染

    window:是用来存放系统API的

    通过var在script中声明的变量,会存储在window里面,就是全局污染–把自定义的放在系统的API存储的地方就是全局污染

    局部作用域

    js有两个作用域,分别是全局和局部作用域

    全局作用域在浏览器就是window对象

    局部作用域:函数运行时所产生的对象

    函数:静态+触发态

    静态

    如下图,如果没调用函数mian()是否能正常打印a,b,c呢?

    在这里插入图片描述
    结果是没有出现
    在这里插入图片描述

    因为函数只是声明的还没有出发出来,换句话说就是,函数没调用,没调用就相当于没有声明函数所以a,b,c没有被声明

    触发态

    所以当我们调用函数之后就有了值
    在这里插入图片描述
    在这里插入图片描述
    当调用函数之后a,b,c就会被声明

    那么abc存储在那里呢?全局?

    我们在window(全局声明)里面是没看到的

    答案是:函数作用域,这个是在函数运行期间临时生成的,在运行结束的时候会自动销毁

    调试面板DOM断点

    在这里插入图片描述
    本地创建的临时作用域
    在这里插入图片描述

    如何解决全局污染

    举例

    代码如下

    <body>
      <script>
        var a=10,b=20
        console.log(a+b);
        console.log('全局:',window);
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果产生了全局污染
    在这里插入图片描述

    解决方法:把代码在函数里执行–利用局部作用域结局全局变量污染,变量自然会存储在函数作用域而且执行完毕后,还会释放内存
    而全局window声明变量直到页面管不,储存在这里的函数会一直存活下去,直到页面关闭

    匿名函数自调用

    注意点:和上一行要有一个分号间隔,要不然可能会产生错误,也可以在前面加一个分号,没上一行则可以不用间隔
    为什么匿名:没名字的函数,仅仅是为了执行一次而已,提供一个局部作用域
    格式

    <body>
      
      <script>
        (function(){
          // 代码写在函数里,所有声明的代码都在函数作用域
        })();
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    所以代码可以这样写

    <body>
      <script>
        ;(function(){
          var a=10,b=20;
          console.log(a+b);
        console.log('全局:',window);
        })()
      script>
    body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果:这次没有污染全局作用域
    在这里插入图片描述
    为什么不会产生全局污染呢?

    如下图
    在这里插入图片描述

    原因:因为生成的变量等是放在函数作用域里面的,使用完之后会销毁掉所以不会对全局产生污染

    在这里插入图片描述

    声明提升

    声明提升:JS的编辑器会先阅读提取代码中的声明操作然后提到顶部在去执行调整过顺序的代码

    首先来看两demo,来了解一下声明提升

    demo1

    在这里插入图片描述

    除了js之外的语言类似的代码都是打印:‘1111,2222’这是JS的特殊设定,

    因为JS引擎会把声明代码进行提升然后再去执行如下图
    在这里插入图片描述

    demo2

    在这里插入图片描述

    结果

    在这里插入图片描述

    解析

    var a=function(){
    	console.log(1);
    }
    
    • 1
    • 2
    • 3

    是由两行代码合并起来的
    拆开就是

          var a 
          //声明操作
          a=function(){
            console.log(1);
          }
          // 赋值操作
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当JS在处理时…
    在这里插入图片描述

    闭包与作用域链

    看下案例
    在这里插入图片描述

    函数分为两种状态:静态和动态(调用)
    函数为什么能用到外部的声明——作用域链

    作用域链

    当出现多层作用域嵌套的时候
    会一层一层往上去找——就近原则-优先使用离得比较近的在这里插入图片描述
    比如下面这个案例打印的就是小新

    在这里插入图片描述
    优先使用最近的

    局部作用域-函数作用域:·临时生成的对象,函数运行结束后会销毁,达到节省内存的目的

    看示例猜猜下面的结果看:

     <script>
        // 函数分为两种状态:静态和动态(调用)
        // var uname="小宝"
        function show(){
          var uname ='小新'
          var b=function(){
            console.log(uname);
          }
          // b()
          return b
        }
        var b=show()  //show函数调用后的结果
        b()
      </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    为什么会有结果呢?

    解析:如果在一个函数作用域内,例如在b函数里面uname在另外一个函数中被使用了,而我们为了确保函数能永远正常运行,JS就会让这个b函数 把用到的uname所用到的作用域保存下来,防止被其释放,导致无法使用

    运行:

     console.dir(b)
    
    • 1

    在这里插入图片描述
    简单的来说就是能用到的数据,会连作用域一起宝留下来不会被销毁

    闭包

    闭包用于形容被保存下来的函数作用域
    在这里插入图片描述
    相当于
    在这里插入图片描述
    再来看一个案例

        <script>
          (function () {
            var a = 10;
            var b = 20;
            function x() {
              var a = 30;
              var c = 40;
              function y() {
                var d = 30;
                function z() {
                  var e = 60;
                  console.log(a, b, c, d, e);
                  // ?
                }
                z();
              }
              y();
            }
            x();
          })();
        script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    函数scopes属性:储存·使用到的··来自其他作用的变量 所在的作用域——防止其他作用域自动销毁
    已知e是自己作用于的
    所以就为:

    在这里插入图片描述

    由于就近原则所以scopes的数组大致就为:

     scopes:[
    	0:closure y(d:50)
    	1:closure x(b:30,c:40)
    	2:closure (a:10)
    	3:galobal window //全局
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接下来验证一下
    在这里插入图片描述
    事实证明的是对的

    函数的私有属性

    私有只能自己,不让别人用

    举例

      <script>
        // 只能自己,不让别人用
        (function(){
          var money=1000
          function shan_bigjian(){
            money-=100
            console.log("做了个大保健还有:",money,"元")
          }
          shan_bigjian()
          shan_bigjian()
          // 小新也去做了大保健还是pro max
          function xin_bigjian(){
            money-=300
            console.log("小新用阿山的钱做了个大保健还有:",money,"元")
          }
          xin_bigjian()
          xin_bigjian()
          
          
        })()
      script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    如何不让阿山的钱被小新用 ?

    实现方式

    方式:把money放在一个函数作用域里运行不放在公开的位置(不放在自己显眼的位置,自己带着)—使用匿名函数快速制作一个私有的作用域
    在这里插入图片描述
    修改后就为:
    在这里插入图片描述
    在这里插入图片描述
    现在只能自己用了

    但是现在只能在内部用,我想在外部函数使用(相当于只能偷偷用,我想光明正大的用)
    实现:
    在这里插入图片描述
    在这里插入图片描述

    现在数据只能拥有的函数可以用了,其他函数用不了【小新就无法使用阿山的钱了】

    解析:
    在这里插入图片描述

    函数重载

    函数重载:可以让函数功能增强变为多功能函数
    比如:制作一个双十一折扣价格的函数的

    demo

      <body>
        <script>
          // 制作一个双十一折扣价格的函数的
          function zhekou(x, y, z) {
            // console.log(typeof y);
            // arguments保存了函数触发时收到的所有实参
            if (arguments.length == 3) {
              // 满减
              // console.log(arguments);
              if (x <= y) {
                return x - z;
              } else {
                return x;
              }
            } else if (arguments.length == 2) {
              // 打折/vip
              // console.log(arguments);
              if (typeof y == "string") {
                if (y == "vip1") {
                  return x * 0.7;
                } else if (y == "vip2") {
                  return x * 0.55;
                }
              } else if (typeof y == "number") {
                return x * y;
              }
            }
          }
          console.log(zhekou(3000, 0.7));
          console.log(zhekou(1000, 0.9));
          console.log(zhekou(1000, "vip1"));
          //0.8折
          console.log(zhekou(1000, "vip2"));
          //0.55折
          console.log(zhekou(2000, 2000, 500));
          //满两千-500
          console.log(zhekou(2000, 2000, 700));
          //满两千-700
        script>
      body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    结果
    在这里插入图片描述

    解析

    实现判断满多少减多少和折扣的判断:因为arguments存了传入的所有数据,所有用arguments.lengch来判断参数
    实现折扣和vip优惠:判断第二个数据类型使用typeof,但是对比的参数最好时字符【带引号,不加会报错】
    数据返回:return返回的数据,不会直接打印出来,要打印一下

    轻松一下

    请用3s秒找到下面的错误

    <script>
    var bnumm = (function () {
      var num = 100;
      return function b() {
        num--;
        console.log("b is num", num);
        b();
      };
    })();
    bnumm();
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    设计模式介绍
    TCP/IP 三次握手&四次挥手详解,以及异常状态分析
    RabbitMQ--延迟队列--使用/原理
    Android Studio的笔记--aidl实现和调用
    数据分析——对比思维、A/B test
    第7章 函数--C++的编成模块
    初识C语言——详细入门(系统性学习day4)
    Windows超级管理器
    IEEE AJE期刊润色 流程记录
    项目管理范围(上)
  • 原文地址:https://blog.csdn.net/weixin_50112395/article/details/126048766