2023/2/28日笔记

83 阅读4分钟

1-10、闭包的记忆

闭包的记忆性举例

  • 创建体温函数checkTemp(n),可以检查体温n是否正常,函数会返回布尔值。
  • 但是不同的小区有不同的体温检测标准,比如A小区体温合格线是37.1℃,而B小区体温合格线是37.3℃,应该怎么编程呢
  • 注:会在代码案例中体现

代码案例

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1-10、闭包的记忆</title>
</head>

<body>
    <script>
        function createCheckTemp(standardTemp) {
            function CheckTemp(n) {
                if (n <= standardTemp) {
                    alert("你是个正常人")
                } else {
                    alert("你不正常,跟我走吧")
                }
            }
            return CheckTemp;
        }
        // 创建一个CheckTemp函数,它以37.1为标准
        var CheckTemp_A = createCheckTemp(37.1);
        // 再一个CheckTemp函数,它以37.2为标准
        var CheckTemp_B = createCheckTemp(37.2);
        // 在一个CheckTemp函数,它以37.3为标准
        var CheckTemp_C = createCheckTemp(37.3);
        // 再一个CheckTemp函数,它以37.4为标准
        var CheckTemp_D = createCheckTemp(37.4);
        CheckTemp_A(37.0)
        CheckTemp_A(38.0)
        CheckTemp_B(37.0)
        CheckTemp_B(38.0)
        CheckTemp_C(37.0)
        CheckTemp_C(38.0)
        CheckTemp_D(37.0)
        CheckTemp_D(38.0)
    </script>
</body>

</html>

1-11、闭包的应用

闭包用途2 - 模拟私有变量

  • 题目请定义一个变量a,要求是能保证这个a只能被指定操作(如加1、乘二),而不能进行其他操作,应该怎么编程呢?
  • 在Java、C++等语言中,有私有属性的概念,但是JavaScript中只能用闭包来模拟。

使用闭包的注意点

  • 不能滥用闭包,否则会造成网页发性能问题,严重时可能导致内存泄漏。所谓内存泄漏是指程序中已动态分配的内存由于某种原因未释放或无法释放。

image.png

  • 注:最终输出结果是1;1;2;2;

代码案例

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1-11、闭包的应用</title>
</head>
<body>
    <script>
        // 封装一个函数,这个函数的功能就是私有化变量
        function fun() {
            // 定义一个局部变量
            var a = 0;

            // return function() {
            //     alert(a);
            // }
            return {
                getA: function() {
                    return a;
                },
                add: function() {
                    a++;
                },
                pow: function() {
                    a *= 2;
                },
            };
        }

        // var getA = fun();
        // getA
        var obj = fun();
        // 如果想在fun函数外面使用变量a,唯一的方法就是调用getA()方法
        console.log(obj.getA());
        // 想让变量a进行加1操作
        obj.add();
        obj.add();
        obj.add();
        console.log(obj.getA());
        obj.pow();
        console.log(obj.getA());


        // 使用闭包的注意点
        // 不能滥用闭包,否贼会造成网页的性能问题,严重时可能导致内存泄漏。
        // 闭包面试题
        function addCount() {
            var count = 0;
            return function () {
                count = count + 1;
                console.log(count);
            }
        }
        var fun1 = addCount();
        var fun2 = addCount();
        fun1();
        fun2();
        fun2();
        fun1();
    </script>
</body>
</html>

1-12、立即执行函数IIFE

什么是IIFE

  • IIFE(immediately Invoked Function Expression,立即调用函数表达式)是一种特殊的JavaScript函数写法,一旦被定义,就立即被调用

image.png

形成IIFE的方法

  • 函数不能直接加圆括号被调用。
  • 函数必须转为“函数表达式”才能被调用。

image.png

IIFE的作用1 - 为变量赋值

  • 为变量赋值:当给变量赋值需要一些较为复杂的计算时(如if语句),使用IIFE显得语法更紧凑

image.png

IIFE的作用2

image.png

IIFE的作用 - 将全局变量变为局部变量

  • IIFE可以在一些场合(如for循环中)将全局变量变为局部变量,语法显得紧凑。

image.png

代码案例

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1-12、立即执行函数IIFE</title>
</head>

<body>
    <script>
        // 为变量赋值
        // var age = 12;
        var age = 42;
        // var sex = "男";
        var sex = "女";
        var title = (function () {
            if (age < 18) {
                return "小朋友"
            } else {
                if (sex == "男") {
                    return "先生"
                } else {
                    return "女士"
                }
            }
        })();
        alert(title);

        // IIFE的作用2:将全局变量变为局部变量
        var arr = [];

        for (var i = 0;i < 5; i++) {
            (function (i) {
                arr.push(function () {
                    alert(i);
                });
            })(i);
        }
        arr[2]();
    </script>
</body>

</html>

2-1、认识对象

认识对象

  • 对象(object)是“键值对”的集合,表示属性和值的映射关系

image.png

对象的语法

  • k和v之间用冒号分隔,每组k:v之间用逗号分隔,最后一个k:v对后可以不书写逗号

image.png

属性是否加引号

  • 如果对象的属性键名不符合JS标识符命名规范,则这个键名必须用引号包裹

image.png

属性的访问

  • 可以用“点语法”访问对象中指定键的值

image.png

  • 如果属性名不符合JS标识符命名规范,则必须用方括号的写法来访问

image.png

  • 如果属性名以变量形式存储,子必须使用方括号形式

image.png

属性的更改

  • 直接使用赋值运算符重新对某属性赋值即可更改属性

属性的创建

  • 如果对象本身没有某个属性值,则用点语法赋值时,这个属性会被创建出来

属性的删除

  • 如果要删除某个对象的属性,需要使用delete操作符

代码案例

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2-1、认识对象</title>
</head>
<body>
    <script>
        // 对象的声明与调用
        var xiaoming = {
            name: "小明",
            age: 12,
            sex: "男",
            hobbies: ["足球","编程"],
            "favorite-book":"苏克和贝塔",
        };
        console.log(xiaoming.age);
        console.log(xiaoming.hobbies);
        console.log(xiaoming.name);
        console.log(xiaoming.sex);

        console.log(xiaoming["favorite-book"]);

        var key = "sex";
        console.log(xiaoming[key]);

        // 属性的更改
        var obj = {
            a: 10,
            b: 20
        };

        // 对象属性的修改
        obj.b = 40;
        obj.b++;
        console.log(obj.b);
        
        // 对象属性的增加
        obj.c = 60;
        console.log(obj);
        
        // 对象属性的删除
        delete obj.a;
        console.log(obj);
    </script>
</body>
</html>

2-2、对象的方法

对象的方法

  • 如果某个属性值是函数,则它也被称为对象的“方法”

image.png

方法的调用

  • 使用“点语法”可以调用对象的方法

方法和函数

  • 方法也是函数,只不过方法是对象的“函数属性”,它需要用对象打点调用
  • 在正式学习了什么是“方法”之后,就能深入理解之前我们学习的一些函数的书写形式了,比如:

image.png

代码案例

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2-2、对象的方法</title>
</head>
<body>
    <script>
        var xiaoming = {
            name: "小明",
            age: 12,
            sex: "男",
            sayHello: function () {
                console.log("你好我是小明,我12岁了,我是一个男生");
            },
            sleep: function () {
                console.log("小明开始睡觉zzzzzz");
            }
        }
        xiaoming.sayHello();
        xiaoming.sleep();

        var xiaohong = {
            name: "小红",
            age: 11,
            sex: "女",
            sayHello: function () {
                console.log("你好我是小红,我11岁了,我是一个女生");
            },
            sleep: function () {
                console.log("小红开始睡觉zzzzzz");
            }
        }
        xiaohong.sayHello();
        xiaohong.sleep();

    </script>
</body>
</html>

2-3、对象的遍历

对象的遍历

  • 和遍历数组类似,对象也可以被遍历,遍历对象需要使用for...in...循环
  • 使用for...in...循环可以遍历对象的每个
  • 在后续的ES6相关课程中,还会学习新的对象遍历的方式

for...in...循环

image.png

代码案例

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2-3、对象的遍历</title>
</head>

<body>
    <script>
        var obj = {
            a: 11,
            b: 22,
            c: 88,
        };
        for (var k in obj) {
            console.log("对象obj的属性" + k + "的值是" + obj[k]);
        }
    </script>
</body>

</html>

2-4、对象的浅克隆

复习基本类型值和引用类型值

  • 还记得我们之前学习过的基本类型值和引用类型值么?

image.png

对象是引用类型自豪

  • 对象是引用类型值,这意味着
    • 不能用var obj2 = obj1这样的语法克隆一个对象
    • 使用==或者===进行对象的比较是,比较的是他们是否为内存中的同一个对象,而不是比较值是否相同

对象的浅克隆

  • 复习什么是浅克隆:只克隆对象的“表层”,如果对象的某些属性值又是引用类型值,则不进一步克隆它们,只是传递它们的引用

代码案例

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2-4、对象的浅克隆</title>
</head>
<body>
    <script>
        // 例子1
        var obj1 = {
            a:1,
            b:2,
            c:3,
        };

        var obj2 = {
            a:1,
            b:2,
            c:3,
        };

        // 对象的判断相等/恒等时不仅判断值,也会判断在内存中的地址
        console.log(obj1 == obj2);      // false
        console.log(obj1 === obj2);     // false
        
        console.log({} == {});      // false
        console.log({} === {});     // false

        // 例子2
        var obj3 = {
            a: 10,
        };
        var obj4 = obj3;
        obj3.a ++;
        console.log(obj4);      // {a:11}


        // 实现浅克隆
        var obj5 = {
            a: 1,
            b: 2,
            c: [11,22,33],
        }
        var obj6 = {};
        for (var k in obj5) {
            // 每遍历一个k属性,就给obj6也添加一个同名的k属性
            // 值和obj5的k属性相同
            obj6[k] = obj5[k];
        }

        // 为什么叫浅克隆呢?比如c属性的值是引用类型值,那么本质上obj5和obj6的c属性是内存中的同一个数组,并没有被克隆分开。
        obj6.a++;
        obj6.c.push(99)
        console.log(obj5);      // obj6的c属性这个数组也会被增加77数组
        console.log(obj6);
        console.log(obj5.c == obj6.c);      // true,true就证明了数组是同一个对象
    </script>
</body>
</html>