JavaScript-进阶day3笔记

发布于:2025-09-04 ⋅ 阅读:(14) ⋅ 点赞:(0)


(一)编程思想

一、面向过程
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了。

二、面向对象(oop)
面向对象是把事务分解为一个个对象,然后由对象之间分工与合作。
面向对象的特性:封装性、继承性、多态性

面向过程编程 面向对象编程
优点 性能比面向对象高,适合跟硬件联系很紧密的东西 易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点 没有面向对象易维护、易复用、易扩展 性能比面向过程低

提示:以下是本篇文章正文内容,下面案例可供参考

(二)构造函数

  • 封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。
  • 同样的将变量和函数结合到了一起并能通过 this 实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间是彼此不影响的。

▲ 总结:

  1. 构造函数体现了面向对象的封装特性。
  2. 构造函数实例创建的对象彼此独立、互不影响。

构造函数存在浪费内存的问题。


(三)原型

一、原型

原型(Prototype)是一个对象模板,当创建新对象时,新对象会“关联”到这个模板,从而可以共享模板上的属性和方法。

  • 构造函数通过原型分配的函数是所有对象所共享的。
  • JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象。
  • 这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存。
  • 我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
  • 构造函数和原型对象中的 this 都指向 实例化的对象

反例:不使用原型——重复创建,浪费内存

<script>
     // 构造函数:每次new都会执行内部代码
     function Dog(name) {
         this.name = name
         this.bark = function() {
             console.log(`${this.name}汪汪叫`)
         }
     }

     // 创建两个实例
     const dog1 = new Dog('大黄')
     const dog2 = new Dog('小白')

     // 验证:两个实例的bark是不同的函数(内存中存了两份相同逻辑)
     console.log(dog1.bark === dog2.bark)  //false(浪费内存!)
 </script>

问题:100个狗实例就会创建100个bark方法,逻辑完全一样,却占用100份内存——这就是原型要解决的核心痛点。

正例:使用原型——共享方法,节省内存

<script>
     function Dog(name) {
         this.name = name
     }

     // 关键:把共享方法放在原型上(所有实例共用这一个bark方法)
     Dog.prototype.bark = function() {
         console.log(`${this.name} 汪汪叫`)
     }

     // 创建两个实例
     const dog1 = new Dog('大黄')
     const dog2 = new Dog('小白')

     // 验证:两个实例的bark指向同一个函数(内存中只存一份)
     console.log(dog1.bark === dog2.bark)  //true(节省内存!)

     // 实例调用方法:自身没有bark,就去原型 (Dog.prototype) 中找
     dog1.bark()  //大黄 汪汪叫
     dog2.bark()  //小白 汪汪叫
 </script>

二、constructor 属性:指向构造函数

constructor 是原型对象上的一个属性,指向创建该对象的构造函数(用于标识对象的“类型”)。

案例:constructor 的作用

<script>
    // 1.定义构造函数(用于创建对象的“工厂”)
    function Person(name) {
        this.name = name
    }

    // 2.创建实例
    const person1 = new Person('大鱼')

    // 3.访问constructor
    console.log(person1.constructor)  //输出: function Person(name) {...}
    console.log(person1.constructor === Person)  //true(证明是Person构造的)
</script>

🔺注意:
constructor 可被修改,因此不能完全依赖它判断类型(更可靠的是 Object.prototype.toString.call)。

1. constructor 的默认指向
当你创建一个构造函数时,JS 会自动做两件事:

  • 给构造函数添加 prototype 属性,指向一个“原型对象”。
  • 给这个“原型对象”添加 constructor 属性,指向构造函数本身。
function Person() {}
// 自动关联:Person.prototype.constructor = Person
console.log(Person.prototype.constructor === Person)  //true

2. 手动覆盖原型会丢失 constructor
若直接给 prototype 赋值一个新对象,会覆盖默认的原型对象,导致 constructor 指向错误(默认指向 Object)。

反例(错误)

function Person() {}
//直接覆盖原型对象
Person.prototype = {
	sayHi: function() {}
}

const p = new Person()
console.log(p.constructor)
//输出:function Object() {...}  (错误,应为Person)

在这里插入图片描述

正例(修复)
覆盖原型时,手动重置 constructor:

<script>
    function Person() {}
    Person.prototype = {
        constructor: Person,
        sayHi: function() {
            console.log('Hi')
        }
    }

    const p = new Person()
    console.log(p.constructor === Person)  //true
</script>

三、对象原型:__proto__prototype

  • prototype:属于构造函数的属性,指向“原型对象”(模板)。
  • __proto__:属于实例对象的属性,指向其“原型对象"(即构造函数的prototype)。
<script>
    function Person(name) {
        this.name = name
    }

    const person1 = new Person('张三')

    // 关键等式:实例的 __proto__ === 构造函数的prototype
    console.log(person1.__proto__ === Person.prototype)  //true
</script>

__proto__ 是浏览器提供的“访问器”,
标准写法是 Object.getPrototypeOf (实例)

概念 归属 作用 标准性
prototype 构造函数 指向 “原型对象”,是实例的 “模板来源” 标准属性
proto 实例对象 指向实例的 “原型对象”,是查找链的入口 非标准访问器
Object.getPrototypeOf(实例) 全局方法 标准方式获取实例的原型 (替代 proto) 标准方法

四、原型继承

通过将方法定义在构造函数 prototype 上,所有实例可共享该方法(避免每个实例重复创建方法,节省内存)。

// 1. 构造函数(只定义实例自身的属性)
function Person(name) {
  this.name = name;
}

// 2. 在原型上定义共享方法(所有实例共用)
Person.prototype.sayHi = function() {
  console.log(`你好,我是${this.name}`);
};

// 3. 创建两个实例
const person1 = new Person("张三");
const person2 = new Person("李四");

// 4. 实例调用共享方法
person1.sayHi(); // 输出:你好,我是张三
person2.sayHi(); // 输出:你好,我是李四

// 证明方法是共享的(两个实例的方法指向同一个地址)
console.log(person1.sayHi === person2.sayHi); // 输出:true

五、原型链:属性查找的“链条”

当访问对象的某个属性时,JS 会先在对象自身查找;
若找不到,会沿着 __proto__ 向上查找其“原型对象”;
若仍找不到,继续向上查找原型的原型,直到 Object.prototype (顶层原型);
若最终找不到,返回 undefined
这个查找链条就是原型链

function Person(name) {
  this.name = name;
}
// 原型1:Person 的原型
Person.prototype.age = 18;
// 原型2:顶层原型(Object 的原型)
Object.prototype.gender = "未知";

const person1 = new Person("张三");

// 1. 查找自身属性:name(存在)
console.log(person1.name); // 输出:张三(自身有)

// 2. 自身没有 age,沿 __proto__ 找 Person.prototype(存在)
console.log(person1.age); // 输出:18(来自 Person.prototype)

// 3. 自身和 Person.prototype 都没有 gender,继续找 Object.prototype(存在)
console.log(person1.gender); // 输出:未知(来自 Object.prototype)

// 4. Object.prototype 没有 abc,查找结束,返回 undefined
console.log(person1.abc); // 输出:undefined

网站公告

今日签到

点亮在社区的每一天
去签到