JavaScript的原型对象、实例和构造函数的关系

1、什么是构造函数?

        构造函数(Constructor)的本身其实就是我们常用的函数,传入一个或者多个参数,处理出我们想要的一个结果;而用于创建和初始化对象的函数,就称之为构造函数(Constructor);常见的就是当我们使用“new”关键字去实例化一个函数的时候,此时,这个函数就被称为构造函数。

// 这就是一个是函数
function MyWorld(name, grade, figure) {
    this.userId = {
        name: name,
        grade: grade,
        figure: figure
    }
    // this.userId = {name, grade, figure}
}

// 此时,被调用实例化的函数就称之为构造函数
const myworld = new MyWorld('史蒂芬', '0', '形象1')

       构造函数其实就是函数,只是和普通函数用的地方不一样,所以换了个名字便于区分而已。

        注意:构造函数内使用this来初始化值是因为this的指向在new实例化后会指向新创建的对象,对this指向不熟悉的可以回顾一下 《点击这里》

        1.1、这就是构造函数

        构造函数(Constructor)是JavaScript中用于创建和初始化对象的特殊函数,作为对象的模版,定义了对象的初始化状态和基本结构,当使用“new”关键字调用构造函数时,它会创建一个新的对象实例。

        1.2、构造函数的三大核心特征

        1. 命名约定:通常以大写字母开头(区别于普通函数)。

        2. 使用 this 关键字:在函数内部使用 this 设置实例属性。

        3. 配合 new 操作符:通过 new 关键字创建实例。

        1.3、构造函数的工作原理

        当使用 new 调用构造函数时,JavaScript 引擎会执行以下步骤:

        1. 创建新对象:在内存中创建一个新的空对象  { }

        2. 设置原型链:将新对象的原型(__proto__)指向构造函数的 prototype 属性。

        3. 绑定 this:将构造函数中的 this 绑定到这个新对象。

        4. 执行构造函数:运行构造函数内部的代码(初始化对象)。

        5. 返回对象:自动返回新创建的对象(除非显式返回其它对象)。

        1.4、构造函数和普通函数的对比
特性构造函数普通函数
调用方式必须使用 new 关键字直接调用
命名约定首字母大写首字母小写
返回值隐式返回新对象(this显示返回值或 undefined
this 指向指向新创建的实例取决于调用上下文
用途创建对象实例执行特定任务
2、什么是实例?

        在面向对象编程中,实例是指通过类(Class)或者构造函数(Constructor)创建的具体对象,每个实例都是根据 类 / 构造函数 的基础信息创建出来的独立的实体,拥有自己的属性和方法。

// 类
class MyWorld {
    constructor(name, grade, figure) {
        this.name = name
        this.grade = grade
        this.figure = figure
    }

    // 实例方法
    SpaceJump(key) {
        if (key === 'Space' || key === ' ') {
            console.log(`${this.name}触发了跳跃`)
        }
    }

    // 静态方法
    static EnterChat(key) {
        if (key === 'Enter') {
            console.log('触发了聊天')
        }
    }
}

const myworld1 = new MyWorld('史蒂芬', '0', '形象1')

const myworld2 = new MyWorld('我不叫菜只因', '0', '自定义形象')

// 这里的 myworld1 和 myworld2 是两个独立的实体

        myworld1 和 myworld2 是两个独立的实体,以下是输出:

        再比如一些常见的实例:

// DOM元素实例,每个DOM元素都是 HTMLElement的实例
const button = document.createElement("button")
console.log(button instanceof HTMLElement) // true
button.textContent = "Click me"

// 日期对象,Date对象的实例标识特定时间点
const now = new Date()
const birthday = new Date("2000-5-29")
console.log(now.getFullYear()) // 当前年份
console.log(birthday.getDay()) // 生日是周几
        1.1、实例的核心要点

        1. 具体对象:实例是根据类 / 构造函数创建的具体对象。

        2. 独立状态:每个实例有自己独立的属性值。

        3. 共享行为:同类实例共享方法(通过原型)

        4. 创建方式:使用 new 关键字创建。

        5. 面向对象基础:实例是实现封转、继承和多态的基础。

3、什么是原型对象,以及三者的关系(原型对象、构造函数和实例)

        原型对象(Prototype)是JavaScript实现继承和共享属性的核心机制。每个JavaScript对象(除 ‘null’ 外)在创建时都会关联另一个对象,这个关联对象就是原型对象。当访问对象的属性时,如果对象自身没有该属性,JavaScript会沿着原型链向上查找,直到找到该属性或到达原型链末端。

        下面的代码中详细描述了原型对象(prototype)、构造函数(constructor)和实例之间的关系。

// 类
class MyWorld {
    constructor(name, grade, figure) {
        this.name = name
        this.grade = grade
        this.figure = figure
    }

    // 实例方法
    SpaceJump(key) {
        if (key === 'Space' || key === ' ') {
            console.log(`${this.name}触发了跳跃`)
        }
    }

    // 静态方法
    static EnterChat(key) {
        if ('key' === 'Enter') {
            console.log('触发了聊天')
        }
    }
}

MyWorld.prototype.c_Squat = function() {
    console.log(`${this.name}触发了蹲下`)
}

const myworld1 = new MyWorld('史蒂芬', '0', '形象1')
const myworld2 = new MyWorld('我不叫菜只因', '0', '自定义形象')
      
console.log(myworld1, myworld1.__proto__, MyWorld.prototype)
console.log(myworld1.__proto__.constructor, MyWorld.prototype.constructor, MyWorld)
console.log(myworld1.__proto__.constructor === MyWorld.prototype.constructor)
console.log(MyWorld.prototype.constructor === MyWorld)
console.log(myworld1.__proto__.constructor === MyWorld)
console.log(myworld1, myworld2)

        以下是运行结果,便于对比熟悉:

4、原型对象的四大特性
        4.1、原型链继承机制

        1. 对象通过 __proto__ 属性连接原型(现代代码应使用 Object.getPrototypeOf())。

        2. 属性查找路径:对象自身 → 原型 → 原型的原型 → ... ... → null。

        3. 原型链的终点:Object.prototype.__proto__ === null。

        4.2、构造函数与原型

        1. 每个函数都有 prototype 属性(指向原型对象)。

        2. 原型对象自动获得 constructor 属性(指向构造函数)。

        3. 实例通过 __proto__ 连接构造函数的原型。

        4.3、共享属性与方法

        1. 定义在原型上的方法被所有实例共享。

        2. 避免每个实例重复创建方法,节省内存。

        4.4、动态修改

        1. 原型修改立即影响所有实例。

        2. 即使实例在修改前已创建。

        4.5、原型操作的三类方法

        1. 原型访问

const obj = {
  name: 'obj',
  id: 1
}

const newProto = {
  name: 'newProto',
  id: 2
}

// 获取原型(推荐)
const proto = Object.getPrototypeOf(obj)

// 设置原型(谨慎使用)
Object.setPrototypeOf(obj, newProto)

// 非标准历史方法(避免使用)
console.log('obj', obj)
console.log('obj.__proto__', obj.__proto__)

        输出结果

        2. 属性检测

// 检查对象自身属性
obj.hasOwnProperty('name') // true

// 检查整个原型链
'toString' in obj // true

// 获取所有属性(包括原型链)
Object.keys(obj) // 自身可枚举属性
Object.getOwnPropertyNames(obj) // 自身所有属性

        输出结果

        3. 原型创建

// 基于现有原型创建
const newObj = Object.create(obj)

// 纯字典对象(无原型)
const pureDict = Object.create(null)
pureDict.toString // undefined

        输出结果

        4.6、原型继承的三种模式

        1. 经典继承(组合继承)

function Parent(name) {
  this.name = name
}
Parent.prototype.sayName = function() {
  console.log(this.name)
}

function Child(name, age) {
  Parent.call(this, name) // 继承属性
  this.age = age
}

// 继承方法
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child // 修复constructor

// 添加子类方法
Child.prototype.sayAge = function() {
  console.log(this.age)
};
console.log('Parent', Parent.prototype)
console.log('Child', Child.prototype)

        输出结果

        2. 原型式继承(Object.create)

const personProto = {
  introduce() {
    return `I'm ${this.name}, ${this.age} years old`;
  }
};

const john = Object.create(personProto);
john.name = "John";
john.age = 30;

console.log('john', john)

        输出结果

        3. ES6类继承(语法糖)

class Vehicle {
  constructor(wheels) {
    this.wheels = wheels;
  }
  
  info() {
    return `Has ${this.wheels} wheels`;
  }
}

class Car extends Vehicle {
  constructor(model) {
    super(4); // 调用父类构造
    this.model = model;
  }
  
  // 方法覆盖
  info() {
    return `${this.model}: ${super.info()}`;
  }
}

const vehicle = new Vehicle('这是Vehicle')
const car = new Car('这是Car')

console.log('vehicle', vehicle)
console.log('vehicle.info()', vehicle.info())
console.log('car', car)
console.log('car.info()', car.info())

        输出结果

        4.7、原型系统的六大关键点

        1. 所有对象都有原型(除了 Object.create(null) 创建的对象)

        2. 函数也是对象,因此函数也有原型

function foo() {}
console.log(Object.getPrototypeOf(foo) === Function.prototype); // true

        3. 内置构造函数的原型

Array.prototype.__proto__ === Object.prototype  // true
Function.prototype.__proto__ === Object.prototype  // true
Object.prototype.__proto__ === null  // true

        4. 原型与性能:过长的原型链会影响查找性能

        5. 原型污染:修改内置原型可能引发意外行为

// 危险操作!
Array.prototype.push = function() { 
  console.log("Array push modified!");
};

        6. 现代替代方案:ES6类语法是原型的语法糖,更易理解

        4.8、原型对象总结表
特性描述
本质实现继承和属性共享机制
核心关系构造函数 ⇄ 原型对象 ⇄ 实例
关键属性prototype(函数),__proto__(实例),constructor(原型)
内存优势共享方法节省内存
动态性修改原型立即影响所有实例
终点Object.prototype 的原型是 null
最佳实践方法放在原型上,属性放在构造函数中

        理解原型对象是掌握 JavaScript 核心的关键,它揭示了 JavaScript 不同于传统类继承语言的独特继承模型——基于原型的继承。随着 ES6 类的普及,虽然语法更接近传统面向对象编程,但底层仍然基于原型系统。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值