JavaScript创建对象与构造函数

目录

创建对象

一、创建对象的 5 种核心方式

1. 对象字面量(直接量)

2. 使用 Object.create()

3. 工厂模式

4. 构造函数模式

5. ES6 class 语法(语法糖)

二、构造函数与 new 关键字

1. 构造函数的作用

2. 构造函数的特征

3. new 关键字的执行机制

三、构造函数 vs 工厂函数对比

四、原型链与构造函数的关系

五、常见问题与解决方案

1. 忘记使用 new 导致问题

2. 方法重复创建(内存浪费)

六、总结

实例成员与静态成员

一、实例成员(Instance Members)

1. 定义与特点

2. 内存模型

二、静态成员(Static Members)

1. 定义与特点

2. ES6 class 中的静态成员

三、实例成员 vs 静态成员

四、关键使用场景

1. 实例成员的典型应用

2. 静态成员的典型应用

五、继承与静态成员

1. ES6 class 的静态继承

2. ES5 手动实现静态继承

六、常见问题与解决方案

1. 静态方法中访问实例成员

2. 实例方法误用 this 访问静态成员


创建对象

一、创建对象的 5 种核心方式

1. 对象字面量(直接量)

特点:最简洁的方式,适合创建简单对象。

const person = {name: "Alice",age: 30,greet() {console.log(`Hello, I'm ${this.name}`);}
};

2. 使用 Object.create()

特点:基于现有对象原型创建新对象,适合原型继承。

const prototypeObj = { type: "Human" };
const person = Object.create(prototypeObj);
person.name = "Bob";

3. 工厂模式

特点:通过函数封装对象创建逻辑,避免重复代码。

function createPerson(name, age) {return {name,age,greet() {console.log(`Hi, I'm ${this.name}`);}};
}
const person = createPerson("Charlie", 25);

4. 构造函数模式

特点:结合 new 关键字创建对象,支持实例化。

function Person(name, age) {this.name = name;this.age = age;this.greet = function() {console.log(`Hello, I'm ${this.name}`);};
}
const person = new Person("David", 28);

5. ES6 class 语法(语法糖)

特点:基于原型的面向对象语法糖,更接近传统面向对象语言。

class Person {constructor(name, age) {this.name = name;this.age = age;}greet() {console.log(`Hi, I'm ${this.name}`);}
}
const person = new Person("Eve", 32);

二、构造函数与 new 关键字

1. 构造函数的作用

定义:用于创建对象的模板函数,通常与 new 关键字配合使用。

  • 初始化对象:定义对象属性和方法。

  • 标识对象类型:通过 instanceof 可检测对象类型。

  • 绑定原型链:通过 prototype 属性实现继承。

示例:

function Person(name, age) {this.name = name;  // 实例属性this.age = age;
}

使用 new 的实例化过程:

  1. 创建空对象,其 __proto__ 指向 Person.prototype

  2. 执行构造函数,将 this 绑定到新对象。

  3. 返回新对象(若构造函数无显式返回对象)。

2. 构造函数的特征

  • 命名约定:通常首字母大写(如 Person),便于区分普通函数。

  • 强制使用 new:若不使用 newthis 会指向全局对象(严格模式下为 undefined),导致意外行为。

    // 错误示例(未使用 new)
    const p = Person("Frank"); 
    console.log(window.name); // "Frank"(污染全局)

3. new 关键字的执行机制

当使用 new 调用构造函数时,发生以下步骤:

function Person(name) {this.name = name;
}// new 的底层模拟(简化版)
function myNew(constructor, ...args) {// 1. 创建一个新对象,并链接到构造函数的原型const obj = Object.create(constructor.prototype);// 2. 执行构造函数,将 this 绑定到新对象const result = constructor.apply(obj, args);// 3. 返回对象(如果构造函数返回对象,则优先返回它)return typeof result === 'object' ? result : obj;
}const person = myNew(Person, "Alice");

详细步骤

  1. 创建空对象:创建一个新对象 obj,其隐式原型(__proto__)指向构造函数的 prototype

  2. 绑定 this:将构造函数内的 this 指向新对象 obj,并执行构造函数代码。

  3. 处理返回值:若构造函数返回一个对象,则返回该对象;否则返回 obj


三、构造函数 vs 工厂函数对比

特性构造函数工厂函数
创建方式new Person()createPerson()
原型链实例的 __proto__ 指向构造函数原型默认无原型链绑定
类型检测instanceof 有效instanceof 无法识别
性能稍优(引擎优化)略低
代码复用通过原型方法共享每个对象独立方法(内存冗余)

四、原型链与构造函数的关系

  • 构造函数:通过 prototype 属性定义共享方法。

  • 实例对象:通过 __proto__ 访问原型链。

  • 继承机制:实例可访问构造函数原型上的属性和方法。

示例

function Person(name) {this.name = name;
}// 在原型上添加方法(共享)
Person.prototype.greet = function() {console.log(`Hi, I'm ${this.name}`);
};const person = new Person("Grace");
person.greet(); // 调用原型方法

五、常见问题与解决方案

1. 忘记使用 new 导致问题

解决方案:在构造函数内部强制 new 调用。

function Person(name) {if (!(this instanceof Person)) {return new Person(name);}this.name = name;
}
const p = Person("Henry"); // 自动补 new
2. 方法重复创建(内存浪费)

问题:构造函数内定义方法会导致每个实例独立一份方法。

function Person(name) {this.name = name;this.greet = function() {}; // 每个实例都有 greet 方法
}

解决:将方法定义在原型上。

Person.prototype.greet = function() {}; // 共享方法

六、总结

  • 对象创建方式:根据场景选择字面量、构造函数、class 等。

  • 构造函数核心:结合 new 实现实例化,通过原型链共享方法。

  • new 的机制:创建对象、绑定原型、执行构造函数、返回对象。

  • 最佳实践:方法定义在原型上,避免内存浪费;使用 class 提升代码可读性。


  

实例成员与静态成员


一、实例成员(Instance Members)

1. 定义与特点
  • 定义:属于实例对象的属性和方法,每个实例独立拥有。

  • 特点

    • 实例属性:通过构造函数内的 this 定义,每个实例独占内存。

    • 实例方法:定义在构造函数的 prototype 上,所有实例共享。

  • 示例

    function Person(name) {this.name = name; // 实例属性(每个实例独立)
    }// 实例方法(共享)
    Person.prototype.sayHello = function() {console.log(`Hello, I'm ${this.name}`);
    };const alice = new Person("Alice");
    alice.sayHello(); // "Hello, I'm Alice"
2. 内存模型
  • 实例属性:每个对象在堆中独立存储。

  • 实例方法:存储在原型对象(Person.prototype)中,所有实例通过原型链共享。


二、静态成员(Static Members)

1. 定义与特点
  • 定义:属于构造函数本身的属性和方法,无需实例化即可访问。

  • 特点

    • 通过构造函数直接调用(如 Array.isArray())。

    • 无法访问实例成员(无 this 指向实例)。

  • 示例

    function Person() {}// 静态属性
    Person.species = "Homo sapiens";// 静态方法
    Person.createAnonymous = function() {return new Person("Anonymous");
    };console.log(Person.species); // "Homo sapiens"
    const anon = Person.createAnonymous();
2. ES6 class 中的静态成员
  • 使用 static 关键字定义:

    class Person {static species = "Homo sapiens"; // 静态属性static createAnonymous() {       // 静态方法return new Person("Anonymous");}
    }

三、实例成员 vs 静态成员

特性实例成员静态成员
归属实例对象构造函数
内存占用属性独立,方法共享全局唯一
访问方式instance.propertyConstructor.property
this 指向实例对象构造函数
适用场景对象状态和行为工具方法、工厂函数、类配置

四、关键使用场景

1. 实例成员的典型应用
  • 描述对象状态(如 person.name)。

  • 定义对象行为(如 person.sayHello())。

2. 静态成员的典型应用
  • 工具函数:无需实例即可调用的功能(如 Math.abs())。

  • 工厂方法:创建特定类型的实例(如 Person.createAnonymous())。

  • 全局配置:类级别的常量或配置(如 Person.DEFAULT_AGE = 30)。


五、继承与静态成员

1. ES6 class 的静态继承
  • 子类自动继承父类的静态成员:

    class Employee extends Person {static role = "Developer";
    }
    console.log(Employee.species); // "Homo sapiens"(继承自 Person)
2. ES5 手动实现静态继承
  • 需显式复制静态成员或设置原型链:

    function Person() {}
    Person.species = "Homo sapiens";function Employee() {}
    // 继承实例方法
    Employee.prototype = Object.create(Person.prototype);
    // 继承静态成员
    Object.setPrototypeOf(Employee, Person);console.log(Employee.species); // "Homo sapiens"

六、常见问题与解决方案

1. 静态方法中访问实例成员
  • 问题:静态方法无实例上下文,无法直接访问实例属性。

  • 解决:通过参数传递实例:

    Person.compareAge = function(person1, person2) {return person1.age - person2.age;
    };
2. 实例方法误用 this 访问静态成员
  • 问题:实例方法中 this 指向实例,无法直接访问静态成员。

  • 解决:通过构造函数名访问:

    Person.prototype.logSpecies = function() {console.log(Person.species); // 正确
    };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/74824.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AIDD-人工智能药物设计-深度学习助力提高儿童低级别胶质瘤复发风险预测的准确性

深度学习助力提高儿童低级别胶质瘤复发风险预测的准确性 儿童低级别胶质瘤(pLGG)是一种常见于儿童患者中的脑肿瘤,尽管大多数时候被认为是良性肿瘤,但是它们仍然可能导致相关症状和并发症的发生,包括但不限于头疼、癫…

redis的数据类型(1)

https://redis.io/docs/latest/develop/data-types/strings/ 社区版支持: String,字符串 Hash,key-value格式 List,根据插入顺序排序 Set,集合 Sorted set,有排序 Stream, Bitmap, …

Nacos配置中心使用

Nacos配置中心 Nacos除了可以做注册中心,🔗Nacos下载和注册中心教程,同样可以做配置管理来使用。 一、统一配置管理 当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就显得十分的不方便,而且很容易出错。我们…

OpenCV轮廓检测全面解析:从基础到高级应用

一、概述 轮廓检测是计算机视觉中的基础技术,用于识别和提取图像中物体的边界。与边缘检测不同,轮廓检测更关注将边缘像素连接成有意义的整体,形成封闭的边界。 轮廓检测的核心价值 - 物体识别:通过轮廓可以识别图像中的独立物体…

Jenkins学习(B站教程)

文章目录 1.持续集成CI2.持续交付CD3.持续部署4.持续集成的操作流程5.jenkins简介6.后续安装部署,见视频 bilibili视频 Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson(Hudson是商用的),主要用…

ARM-UART

时钟选择PLCK,超时3ms自动发送,设置发送8位的缓冲区,且发送中断 设置触发深度,达到8字节将缓冲区数据发憷 中断处理函数

Rust所有权详解

文章目录 Rust所有权所有权规则作用域 内存和分配移动与克隆栈空间堆空间 关于函数的所有权机制作为参数作为返回值 引用与租借垂悬引用 Rust所有权 C/C中我们对于堆内存通常需要自己手动管理,手动申请和释放,即便有了智能指针,对于效率的影…

【在线OJ项目测试报告】

朋友们、伙计们,我们又见面了,本期来给大家带来关于在线OJ项目的测试报告,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数…

【HFP】蓝牙HFP应用层核心技术研究

免提配置文件(Hands-Free Profile, HFP)作为实现设备间音频通信的关键协议,广泛应用于车载系统、蓝牙耳机等场景。本文将基于最新技术规范,深入剖析HFP应用层的功能要求、协议映射及编解码器支持,为蓝牙开发工程师提供详尽的技术指南。 一、HFP应用层功能全景图 HFP定义…

横扫SQL面试——PV、UV问题

📊 横扫SQL面试:UV/PV问题 🌟 什么是UV/PV? 在数据领域,UV(Unique Visitor,独立访客) 和 PV(Page View,页面访问量) 是最基础也最重要的指标&…

【C++】第八节—string类(上)——详解+代码示例

hello,又见面了! 云边有个稻草人-CSDN博客 C_云边有个稻草人的博客-CSDN博客——C专栏(质量分高达97!) 菜鸟进化中。。。 目录 一、为什么要学习string类? 1.1 C语言中的字符串 1.2 面试题(暂不做讲解) …

如何判断JVM中类和其他类是不是同一个类

如何判断JVM中的类是否为同一个类 在Java虚拟机(JVM)中,判断两个类是否相同需要同时满足以下三个条件: 1. 类全限定名必须相同 包括包名类名的完整路径必须完全一致例如:java.lang.String和com.example.String被视为不同类 2. 加载该类的…

ifconfig 使用详解

目录 一、基本语法二、常见用途及示例1. 查看所有网络接口信息2. 启用/禁用网络接口3. 配置 IP 地址和子网掩码4. 修改 MAC 地址5. 启用混杂模式(Promiscuous Mode)6. 设置 MTU(最大传输单元) 三、其他选项四、常见问题1. 新系统中…

1. 标准库的强依赖(核心原因)

1. 标准库的强依赖(核心原因) 容器操作(如 std::vector 扩容) 当标准库容器(如 std::vector)需要重新分配内存时,它会尝试移动现有元素到新内存,而非拷贝(为了性能&…

【MySQL】常用SQL--持续更新ing

一、配置信息类 1.查看版本 select version; 或 select version(); 2.查看配置 show global variables where variable_name in (basedir,binlog_format,datadir,expire_logs_days,innodb_buffer_pool_size,innodb_log_buffer_size,innodb_log_file_size,innodb_log_files_i…

Day82 | 灵神 | 快慢指针 重排链表

Day82 | 灵神 | 快慢指针 重排链表 143.重排链表 143. 重排链表 - 力扣(LeetCode) 思路: 笔者直接给跪了,这个难度真是mid吗 直接去看灵神的视频 环形链表II【基础算法精讲 07】_哔哩哔哩_bilibili 1.简单来说就是&#xf…

常见的微信个人号二次开发功能

一、常见开发功能 1. 好友管理 好友列表维护 添加/删除好友 修改好友信息(备注、标签等) 分组管理 创建/编辑/删除标签 好友分类与筛选 2. 消息管理 信息发送 支持多类型内容:文本、图片、视频、文件、小程序、名片、URL链接等 附加功…

Android打包及上架应用市场问题处理

一、Gradle 配置参数含义: compileSdkVersion: 29 表示项目编译时使用的 Android SDK 版本为 API 29(Android 10),仅影响编译阶段的行为(如代码语法检查、资源处理等),不直接影响运行时兼容性。…

Docker 从入门到进阶 (Win 环境) + Docker 常用命令

目录 引言 一、准备工作 1.1 系统要求 1.2 启用虚拟化 二、安装Docker 2.1 安装WSL 2 2.2 安装Docker Desktop 2.3检查是否安装成功 三、配置Docker 3.1 打开Docker配置中心 四、下载和管理Docker镜像 4.1 拉取镜像 4.2 查看已下载的镜像 4.3 运行容器 4.4 查看正…

计算机视觉5——运动估计和光流估计

一、运动估计 (一)运动场(Motion Field) 定义与物理意义 运动场是三维场景中物体或相机运动在二维图像平面上的投影,表现为图像中每个像素点的运动速度矢量。其本质是场景点三维运动(平移、旋转、缩放等&a…