JavaScript 立即执行函数 面向对象 函数中的this(初步体验)

277 阅读9分钟

JavaScript 立即执行函数 面向对象 函数中的this(初步体验)

前端 JavaScript ES5 学习目录

1. 认识 JavaScript

2. JavaScript 基础语法

3. JavaScript 变量 数据类型 运算操作符

4. JavaScript 逻辑运算符 分支语句 循环语句

5. JavaScript 函数 作用域问题

6. JavaScript IIFE 面向对象 函数中的this

7. JavaScript 类和对象 window对象 常见内置类

8. JavaScript 数组基本使用 Date日期的使用

JavaScript 立即执行函数(Immediately-Invoked Function Express)【IIFE

  • 表达的含义就是我们的函数在被定义完后,就实现我们的立即执行

    • 实现定义我们的立即执行函数的具体的步骤

      • 首先我们是需要先定义一个 匿名函数,这个函数的是具有独立的作用域
      • 然后后面接上一个() ,来具体的实现我们的函数的立即执行
      •     // 立即执行函数的书写方式// 我们先实现我们的没有参数的立即执行函数的书写
            (
              /**javascript
               * 没有参数的立即执行函数的实现
               */
              function(){
                console.log("立即执行函数的执行")
              }
            )()
            ​
            ​
            // 开始实现我们的歹有参数的立即执行函数的实现
            const res = (
              /**
               * 带有参数的立即执行函数
               * @param {Number} num01 
               * @param {Number} num02 
               * @returns 
               */
              function(num01, num02){
                return num01 + num02
              }
            )(10, 20)
            ​
            console.log(res)  // 30
        
    • 立即执行函数和普通代码的区别

      • 表面上来看的话,立即执行函数和普通的函数是没有任何的区别的

      • 但是实现的具体的场景有:

        • 就是我们的立即执行函数可以实现具有自己的作用域的
        • 这样可以实现的是防止全局中的变量的冲突以及变量的污染(因为现在的工作模式是多人开发的
        • 这个时候就出现了我们的立即执行函数来解决这个问题——全局变量命名的冲突以及全局变量的污染
        • 在我们前端早期的开发模式中,就是使用的这种方法来实现的解决我们的变量的污染的
        • 即使是我们的 es6 后面出现了我们的 import / export ,但是实际上的最终的编译后的代码还是我们的 es5 的IIFE
      • 注意我们的 es5 的 var 是不会产生作用域的,这个时候我们使用我们的 IIFE 就可以实现解决我们的这个问题

        • 但是在 es6 中解决这个问题就是十分简单的了

        • <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
          </head>
          <body>
            <div>
              <div class="btn">1</div>
              <div class="btn">2</div>
              <div class="btn">3</div>
              <div class="btn">4</div>
            </div>
          ​
            <script>
              var btnEls = document.querySelectorAll(".btn")
              for (var i = 0; i < btnEls.length; i++) {
                var btn = btnEls[i]
                btn.onclick = function() {
                  console.log(`${i}`)  // 4 4 4 4
                }
              }
            </script>
          </body>
          </html>
          
        • <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
          </head>
          <body>
            <div>
              <div class="btn">1</div>
              <div class="btn">2</div>
              <div class="btn">3</div>
              <div class="btn">4</div>
            </div>
          ​
            <script>
              var btnEls = document.querySelectorAll(".btn")
              for (var i = 0; i < btnEls.length; i++) {
                var btn = btnEls[i];
                (function (i) {
                  btn.onclick = function() {
                    console.log(`${i+1}`)  // 1 2 3 4
                  }
                })(i)
              }
            </script>
          </body>
          </html>
          
        • 比较上面的两行代码,我们是可以发现一点的就是:

          • 两个代码的实现的效果是一点都不同的
          • 首先我们的前端代码的话,我们首先实现的就是我们的先实现基本的从上到小
          • 把所有的代码都执行完,所以说这个时候,就出现了,我们的效果就是全部为 4
          • 但是通过我们的 IIFE 我们就实现解决了这这个问题的出现了(作用域问题

JavaScript 对象类型数据的使用(object)

  • 对象类型的使用

    • 我们的对象类型的数据就是把数据以键值对的形式(key-value)实现保存的一种数据类型

    • 出现我们的对象类型的原因,就是因为我们的以前的那些数据类型只可以实现我们的存储一些简单的值

    • 然后我们需要注意的就是我们的一个对象的数据类型的话具有的属性以及行为

    • // 开始实现书写我们的一个对象
      var person = {
        // 普通的属性
        name: "juwenzhang",
        age: 18,
        height: 185.5,
      ​
        // 定义对象中的方法
        run: function() {
          console.log("running")
        },
        eat: function() {
          console.log("eatting")
        }
      }
      ​
      // 开始实现通过我们的 . 来实现访问我们的对象中的属性
      console.log(person.name)
      console.log(person.age)
      person.run()
      person.eat()
      
    • key 就是实现的是对应的是 property name , value 就是实现的是对应 property value

      • 但是需要注意的是,实质上我们的对象类型中的键的话,是一个字符串类型的数据
    • 学习了 es6 之后,我们就可以发现我们通过 Symbol 定义的数据也是可以作为我们的 key 来实现使用的

  • 实现创建对象的方法

    • 使用对象字面量来实现创建对象(就是使用的是我们的 {})

      • var person = {
            name: "juwenzhang"
        }
        
    • 使用 new Object()

      • var obj = new Object()
        obj.name = "juwenzhang"
        
    • new OtherObj()

      • function Person() {}
        var obj = new Person()
        
  • 对象的使用过程

    • 访问对象的属性

      • var info = {
            name: "juwenzhang",
            age: 18,
            otherInfo: {
                height: 175,
                weight: 110
            },
            running: function() {
                console.log("running")
            }
        }
        ​
        // 实现访问我们的对象的方法就是可以直接通过 . 就可以实现我们的访问对象中的属性
        console.log(info.name)
        console.log(info.otherInfo.height)
        info.running()
        
    • 修改对象的属性

      • // 开始实现修改我们的属性
        info.name = "76433"
        console.log(info.name)  // 76433
        ​
        info.running = function() {
            console.log("我是修改后的方法running")
        }
        info.running()  // 我是修改后的方法running
        
    • 添加对象的属性

      • info.eat = function() {
            console.log("我要吃饭,我饿了!!!")
        }
        ​
        console.log(info)
        
    • 删除对象的属性

      • // 就是实现的是我们的通过 delete 操作符实现的删除对象中的属性
        delete info.name
        delete info.ageconsole.log(info)
        
  • 通过我们的 [] 来实现访问我们的属性

    • var info = {
        name: "juwenzhang",
        age: 18,
        otherInfo: {
            height: 175,
            weight: 110
        },
        running: function() {
            console.log("running")
        }
      }
      ​
      console.log(info["name"])
      console.log(info["age"])
      console.log(info["otherInfo"])
      info["running"]()
      
  • 实现我们的对象的遍历

    • javascript 中对象的遍历的方法就是使用我们的 for in 语法
    • var info = {
        name: "juwenzhang",
        age: 18,
        otherInfo: {
            height: 175,
            weight: 110
        },
        running: function() {
            console.log("running")
        }
      }
      ​
      // 开始实现获取我们对象中的数据// Object.keys()  可以实现的是将我们可迭代对象以一个数组的方式实现返回,
      // 这个就是实现返回的是我们的 property key
      var infokeys = Object.keys(info)
      for(var i = 0; i < infokeys.length; i++) {
        console.log(infokeys[i])
        console.log(info[infokeys[i]])
      }
      ​
      ​
      // 但是实际上 javascript 还给我们提供了更加简便的方式来获取我们的对象中的key
      for(var item in info) {
        console.log(info[item])
      }
      
  • 栈内存和堆内存

    • 我们的一个程序实现运行的时候,都是加载到内存里面实现的我们的运行,但是这个内存的话又分为两个部分:栈内存|堆内存

      • 原始的数据类型(值类型)占用的空间就是在栈内存中实现的分配
      • 对象类型(引用数据类型)占用的空间就是在堆内存中实现的分配

image-20241020194447912.png

image-20241020194724767.png

  • 值类型和引用数据类型

    • 原始的数据类型就是我们的额值类型(number boolean string null undefined symbol
    • 所有的对象类型就是我们的引用数据类型(function array object【函数另外讨论】

image-20241020195252709.png

image-20241020195341006.png

  • 两个对象之间的比较

    • // 现象一
      var obj = {
        name: "juwenzhang",
        other: {
          name: "76433"
        }
      }
      ​
      var other = obj.other
      other.name = "水逆信封"
      console.log(obj.other.name)  // 水逆信封
      // 注意一哈,上面的代码我们需要在浏览器环境下面实现运行,在node环境中会报错的
      
      • 首先我们需要思考的一点是为什么最后是水逆信封??首先我们需要现知道的是我们的 obj.other 是一个对象类型的数据所以说最后实现保存的是我们的内存地址,在后面给我们的 other 进行赋值的时候,也是实现的是赋值这个内存地址的,这个时候就说明了一点,就是我们的 other 也是实现的是访问我们的堆区中的 { name: "76433" },所以说一旦进行了修改,那么最后就是导致实际的值也被修改了,最后就是呈现的我们的输出 1水逆信封
    • // 现象二
      var obj1 = {}
      var obj2 = {}
      console.log(obj1 === obj2)  // false
      
      • 为什么的不相等??根据我们前面说的,每一种引用数据类型的话实际上保存的就是我们的内存地址,两个之间的内存地址不同,所以说就可以说我们的两个对象类型的不同
    • // 值传递和引用传递的区别
      function foo(a) {
          a = 200
      }
      var num = 100
      foo(num)
      console.log(num)  // 100/*
       实现调用我们的函数的时候,我们首先做的就是我们的进行值传递的赋值操作: a = 100   num = 100
       但是当我们的函数内部执行中有: a = 200  num = 100
       最后函数执行完后,函数内部定义的变量全部销毁: num = 100, 这个就是我们的值传递
      */// ======================================================================================var obj = {
        name: "juwenzhang",
        other: {
          name: "76433"
        }
      }
      ​
      function foo(obj) {
        obj.name = "76433"
      }
      ​
      foo(obj)
      console.log(obj.name)  // 76433
      /*
        但是可以自己想一想,如果这个参数是我们的引用数据类型的话,最终可以达到的效果是什么?
        首先我们得引用数据类型的变量保存的是我们的内存地址的,这个时候,通过赋值操作就可以实现形参也是保存的是我们的内存地址
        最终就可以达到我们的通过形参改变我们实参的效果了
        
        还需要注意一点,就是只要含有我们的引用数据类型,那么必定会出现我们的新的内存地址的访问令牌
      */// 可以自己画图来看的哈,我就不画了
      

image-20241020200701920.png

image-20241020202944101.png

JavaScript 函数中的 this

  • 如果我们的函数被某一个对象来引用并且调用,那么这个时候就是实现的是this 指向这个对象

    • 可以实现理解的就是我们的: 只要我们的函数被默认的调用了,那么就是指向的是我们的 window
    • 是由哪一个实现的调用,那么就是实现的指向谁
    • function func(age, name) {
        console.log(arguments)
          console.log(this)  // 默认的是指向的是我们的 window
      }
      
    • var obj = {
        name: "juwenzhang",
        running: function(){
          console.log(this)
        }
      }
      ​
      obj.running()  // 这个时候我们的 this的指向就是我们的 obj
      
  • 开发中 this 的作用

    • 可以通过我们的 this 实现获取得到对象中的有一些属性值, this 指代的是我们的当前的调用对象
    • var obj = {
        name: "juwenzhang",
        running: function() {
          console.log(`${this.name} running`)
        },
        eating: function() {
          console.log(`${this.name} eating`)
        }
      }
      ​
      obj.running()
      
注意一定要把我们的这些基础的数据类型掌握好,因为的话,后面实现我们的前后端交互的时候,从后端返回的数据的,都是需要转化为我们的javascript 中的数据实现操作的,特别是对象的数据类型以及后面会补充的数组的数据类型,这两个都是十分重要的,对于我们而言的话

作图的网址,可以自己用用,挺不错的