2023/3/2日笔记

75 阅读3分钟

2-14、new

用new操作符调用函数

  • 现在,我们学习一种新的函数调用方式:

image.png

  • 你可能知道new操作符和“面向对象”息息相关,但是现在,我们先不探讨它的“面向对象”意义,而是先把用new调用函数的执行步骤和它上下文弄清楚
  • JS规定,使用new操作符调用函数会进行“四步走”
  1. 函数体内会自动创建出一个空白对象
  2. 函数的上下文(this)会指向这个对象
  3. 函数体内的语句会执行
  4. 函数会返回上下文对象,即使函数没有return语句

四步走详解

  • 第1步:函数体内会自动创建出一个空白对象

image.png

  • 第2步:函数的上下文(this)会指向这个对象

image.png

  • 第3步:执行函数体中的语句

image.png

  • 第4步:函数会自动返回上下文对象,即使函数没有return语句

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-14、new</title>
</head>
<body>
    <script>
        function fun() {
            this.a = 3;
            this.b = 6;
            if (this.a > this.b) {
                this.c = 10;
            } else {
                this.c = 20;
            }
        }
        
        // 使用new调用函数时,this指代的是秘密创建出的空对象,当被this.a/b/c时往里面添加了属性和属性值,所以这个时候返回的是这个秘密创建的对象
        var obj = new fun();
        console.log(obj);
    </script>
</body>
</html>

2-15、类与实例

类与实例

image.png

类好比是“蓝图”

  • 如同“蓝图”一样,类只描述对象会拥有哪些属性和方法,但是并不具体指明属性的值

image.png

  • 实例是具体的对象

image.png

类和实例

image.png

  • “狗”是类,“史努比”是实例、“小白”是实例

image.png

构造函数和“类”

image.png

  • Java、C++等是“面向对象”(object-oriented)语言
  • JavaScript是“基于对象”(object-based)语言
  • JavaScript中的构造函数可以类比OO语言中的“类”,写法的确类似,但和真正OO语言还是有本质不同,在后续课程还将看见JS和其他OO语言完全不同的、特有的原型特性

3-1、prototype 和原型链查找

什么是prototype

  • 任何函数都有prototype属性,prototype是英语“原型”的意思
  • prototype属性值是个对象,它默认拥有constructor属性指回函数

image.png

  • 普通函数来说的prototype属性没有任何用处,而构造函数的prototype属性非常有用
  • 构造函数的prototype属性是它的实例的原型

构造函数的prototype是实例的原型

image.png

原型链查找

  • JavaScript规定:实例可以打点访问它的原型的属性和方法,这被称为“原型链查找”

image.png

image.png

image.png

hasOwnProperty

  • hasOwnProperty方法可以检查对象是否真正“自己拥有”某属性或者方法

image.png

in

  • 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>3-1、prototype 和原型链查找</title>
</head>
<body>
    <script>
        function sum(a,b) {
            return a+b;
        }

        // prototype:是一个函数自带的属性,这个代码英文意思是“原型”。prototype的属性值是个对象,它默认拥有constructor属性指回函数
        console.log(sum.prototype);
        console.log(typeof sum.prototype);
        console.log(sum.prototype.constructor === sum);


        function People(name,age,sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        // 实例化
        var xiaoming = new People("小明",12,"男");
        // 测试三角关系是否存在
        console.log(xiaoming.__proto__ === People.prototype);


        function People1(name,age,sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        // 往原型上添加nationality属性
        People1.prototype.nationality = "中国";

        // 实例化
        var xiaogang = new People1("小刚",13,"男");
        var tom = new People1("汤姆",10,"男");
        tom.nationality = "美国";       // 原型链的遮蔽效应

        console.log(xiaogang.nationality);      //  中国
        console.log(xiaogang);

        console.log(tom.nationality);      // 美国

        // 
        console.log(xiaogang.hasOwnProperty("name")); 
        console.log(xiaogang.hasOwnProperty("sex")); 
        console.log(xiaogang.hasOwnProperty("age")); 
        console.log(xiaogang.hasOwnProperty("nationality")); 


        console.log("name" in xiaogang); 
        console.log("sex" in xiaogang); 
        console.log("age"in xiaogang); 
        console.log("nationality" in xiaogang); 
    </script>
</body>
</html>

3-2、在prototype上添加方法

之前,我们将方法写到了对象身上

  • 在之前的课程中,我们把方法都是直接添加到实例身上

image.png

image.png

  • 把方法直接添加到实例身上的缺点:每个实例和每个实例的方法函数都是内存中不同的函数,造成了内存的浪费
  • 解决办法:将方法写到prototype上

方法要写到prototype上

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>3-2、在prototype上添加方法</title>
</head>

<body>
    <script>
        function People() {
            this.sayHello = function () { };
        };

        var xiaoming = new People();
        var xiaogang = new People();
        var xiaohong = new People();

        console.log(xiaoming.sayHello === xiaohong.sayHello);

        function People1(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }

        // 要把方法写在原型上,不然会造成内存浪费
        People1.prototype.sayHello = function () {
            console.log("你好,我是" + this.name + "我今年" + this.age + "岁了");
        }
        People1.prototype.growup = function () {
            this.age++;
        }

        var xiaoming = new People1("小明",12,"男")
        var xiaohong = new People1("小红",11,"女")

        console.log(xiaoming.sayHello === xiaohong.sayHello);

        xiaoming.sayHello();
        xiaohong.sayHello();

        xiaoming.growup();
        xiaoming.growup();
        xiaoming.growup();
        xiaoming.growup();
        xiaoming.growup();
        xiaoming.growup();

        xiaoming.sayHello();
        xiaohong.sayHello();
    </script>
</body>

</html>

3-3、原型链的终点

原型链的终点

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>3-3、原型链的终点</title>
</head>
<body>
    <script>
        function People(name,age) {
            this.name = name;
            this.age = age;
        };
        var xiaoming = new People("小明",12);

        console.log(xiaoming.__proto__.__proto__ === Object.prototype);     // turn
        console.log(Object.prototype.__proto__);                            // null

        // var char = xiaoming.toString();
        // console.log(char);

        console.log(Object.prototype.hasOwnProperty("hasOwnProperty"));     // true
        console.log(Object.prototype.hasOwnProperty("toString"));           // true

        // 数组的原型链
        var arr = [344,45,34,23];

        console.log(arr.__proto__ === Array.prototype);                 // ture
        console.log(arr.__proto__.__proto__ === Object.prototype);     // ture
        console.log(Array.prototype.hasOwnProperty("push"));           // true
        console.log(Array.prototype.hasOwnProperty("splice"));         // true
    
    </script>
</body>
</html>