JavaScript进阶篇——第七章 原型与构造函数核心知识

目录

[1. 构造函数基础](#1. 构造函数基础)

[2. 原型对象(prototype)](#2. 原型对象(prototype))

[3. constructor 属性](#3. constructor 属性)

[4. 对象原型(proto)](#4. 对象原型(proto))

[5. 原型链机制](#5. 原型链机制)

[6. 复习要点速查表](#6. 复习要点速查表)


本文系统讲解了JavaScript构造函数与原型机制。要点包括:1)构造函数封装实例属性和方法,但会造成方法重复创建;2)通过prototype原型对象实现方法共享,节约内存;3)constructor属性保持原型与构造函数的关联;4)proto__形成原型链,实现方法查找机制;5)完整原型链结构为实例→构造函数原型→Object原型→null。最佳实践是将方法定义在原型上、属性放在构造函数中,避免直接使用__proto,重写原型时需修复constructor指向。原型系统通过三大关系(构造函数-原型-实例)实现面向对象特性,有效解决内存浪费问题。

1. 构造函数基础

1.1 封装特性

构造函数是实现面向对象封装的核心工具

复制代码
// ✅ 构造函数封装数据和方法
function Star(uname, age) {
    this.uname = uname;
    this.age = age;
    this.sing = function() {
        console.log('我会唱歌');
    }
}

// 创建实例对象
const ldh = new Star('刘德华', 18);
const zxy = new Star('张学友', 19);

ldh.sing(); // "我会唱歌"
zxy.sing(); // "我会唱歌"

// ❗ 重点:实例对象彼此独立,互不影响
ldh.age = 20;
console.log(zxy.age); // 19(不受影响)

1.2 内存浪费问题

复制代码
// ⚠️ 问题:每个实例都创建自己的方法副本
console.log(ldh.sing === zxy.sing); // false

// 内存结构图示:
// | 实例1 | → | sing方法1 |
// | 实例2 | → | sing方法2 |
// 相同功能的方法被重复创建,浪费内存

2. 原型对象(prototype)

2.1 原型是什么

每个构造函数都有一个prototype属性,指向原型对象

复制代码
function Star(uname, age) {
    this.uname = uname;
    this.age = age;
}

// ✅ 访问构造函数的原型对象
console.log(Star.prototype); // 原型对象(最初为空)

// ✅ 在原型上添加共享方法
Star.prototype.sing = function() {
    console.log('我会唱歌');
}

const ldh = new Star('刘德华', 18);
const zxy = new Star('张学友', 19);

// 验证方法共享
console.log(ldh.sing === zxy.sing); // true(共享同一个方法)

2.2 原型的作用

  1. 共享方法:所有实例共享原型上的方法

  2. 节约内存:方法只创建一次,所有实例共用

  3. 扩展功能:可随时向原型添加新方法

2.3 this指向

构造函数和原型方法中的this都指向实例对象

复制代码
let that;
function Person(name) {
    this.name = name;
    that = this; // this指向即将创建的实例
}

const o = new Person('小明');
console.log(that === o); // true

// 原型方法中的this
Person.prototype.sayHello = function() {
    console.log(`你好,我是${this.name}`);
}

o.sayHello(); // "你好,我是小明"

3. constructor 属性

3.1 作用与位置

每个原型对象都有constructor属性,指向关联的构造函数

复制代码
function Star(name) {
    this.name = name;
}

console.log(Star.prototype.constructor === Star); // true

const ldh = new Star('刘德华');
console.log(ldh.constructor === Star); // true

3.2 使用场景

当重写整个原型对象时,需要手动设置constructor

复制代码
function Star(name) {
    this.name = name;
}

// ❌ 错误写法:重写原型会丢失constructor
Star.prototype = {
    sing: function() {
        console.log("唱歌");
    },
    dance: function() {
        console.log("跳舞");
    }
};
console.log(Star.prototype.constructor); // 指向Object(错误)

// ✅ 正确写法:手动添加constructor
Star.prototype = {
    constructor: Star, // 修复constructor指向
    sing: function() {
        console.log("唱歌");
    },
    dance: function() {
        console.log("跳舞");
    }
};
console.log(Star.prototype.constructor === Star); // true

4. 对象原型(proto

4.1 作用与原理

每个实例对象都有__proto__属性,指向构造函数的原型对象

复制代码
function Star(name) {
    this.name = name;
}

const ldh = new Star('刘德华');

// 对象原型关系
console.log(ldh.__proto__ === Star.prototype); // true
console.log(ldh.__proto__.constructor === Star); // true

4.2 原型链机制

复制代码
// 原型链查找过程:
// 1. 访问ldh.sing()
// 2. 先在ldh实例上查找 → 未找到
// 3. 通过ldh.__proto__找到Star.prototype
// 4. 在Star.prototype上找到sing方法并执行

// ❗ 重点:这就是为什么实例能访问原型上的方法

4.3 注意事项

  1. __proto__是非标准属性(实际开发中避免直接使用)

  2. 标准属性是[[Prototype]],与__proto__意义相同

  3. 可以使用Object.getPrototypeOf()获取原型

  4. __proto__对象原型里也有constructor属性

    // 推荐:使用标准方法获取原型
    console.log(Object.getPrototypeOf(ldh) === Star.prototype); // true

5. 原型链机制

5.1 完整原型链

复制代码
text

实例对象 (ldh)
  ↓ __proto__
构造函数原型 (Star.prototype)
  ↓ __proto__
Object原型 (Object.prototype)
  ↓ __proto__
null

5.2 原型链验证

复制代码
function Star() {}
const ldh = new Star();

// 验证原型链
console.log(ldh.__proto__ === Star.prototype); // true
console.log(Star.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null

6. 复习要点速查表

核心概念关系

概念 位置 指向 作用
prototype 构造函数上 原型对象 存放共享方法
proto 实例对象上 构造函数的prototype 实现原型链查找
constructor 原型对象上 构造函数 表明原型对象的来源

原型系统三大关系

  1. 构造函数 ↔ 原型对象
    构造函数.prototype = 原型对象
    原型对象.constructor = 构造函数

  2. 实例对象 ↔ 原型对象
    实例对象.__proto__ = 构造函数.prototype

  3. 原型对象 ↔ Object原型
    构造函数.prototype.__proto__ = Object.prototype

高频面试题解答

  1. prototype是什么?

    构造函数自动拥有的原型对象,用于存放共享方法

  2. constructor属性在哪里?

    存在于原型对象和对象原型中,指向创建它们的构造函数

  3. __proto__属性在哪里?指向谁?

    在每个实例对象中,指向构造函数的原型对象

  4. 如何解决构造函数的内存浪费问题?

    将方法定义在原型对象上,实现方法共享

  5. 原型链的终点是什么?
    null(Object.prototype.proto === null)

最佳实践

  1. 方法放在原型上:节约内存,实现共享

  2. 属性放在构造函数中:保持实例独立性

  3. 避免直接使用__proto__ :使用Object.getPrototypeOf()

  4. 重写原型时修复constructor:保持正确的构造函数指向

    // ✅ 推荐模式
    function Person(name) {
    // 实例属性
    this.name = name;
    }

    // 原型方法
    Person.prototype.sayHello = function() {
    console.log(你好,我是${this.name});
    };

    // 创建实例
    const p = new Person('小明');
    p.sayHello();

记忆口诀

"构造函数造实例,prototype存共享"

"__proto__连原型,constructor指根源"

"原型链上找方法,层层查找不迷路"

"方法共享省内存,面向对象真强大"

相关推荐
AI 嗯啦1 分钟前
python基础语法9,用os库实现系统操作并用sys库实现文件操作(简单易上手的python语法教学)
开发语言·python
屁股割了还要学13 分钟前
【C语言进阶】内存函数
c语言·开发语言·学习·算法·青少年编程
耳总是一颗苹果15 分钟前
C语言---自定义类型(上)(结构体类型)
c语言·开发语言
玩代码27 分钟前
模板方法设计模式
java·开发语言·设计模式·模板方法设计模式
小飞悟37 分钟前
JavaScript 数组精讲:创建与遍历全解析
前端·javascript
每一天都要努力^1 小时前
C++拷贝构造
开发语言·c++
拾光拾趣录1 小时前
虚拟滚动 + 加载:让万级列表丝般顺滑
前端·javascript
GeminiGlory1 小时前
从0到1开发网页版五子棋:我的Java实战之旅
java·开发语言
然我1 小时前
数组的创建与遍历:从入门到精通,这些坑你踩过吗? 🧐
前端·javascript·面试
豆豆(设计前端)1 小时前
如何成为高级前端开发者:系统化成长路径。
前端·javascript·vue.js·面试·electron