对象创建的4种模式
1. 工厂模式
这种模式抽象了创建具体对象的过程,用函数来封装以特定接口创建对象的细节
缺点:没有解决对象识别的问题(即怎样知道一个对象的类型)
function createPerson(name, age, job) {var o = new Object();o.name = name;o.age = age;o.job = job;o.sayName = function() {alert(this.name)};return o; } const personOne = createPerson('lee', 29, 'Software Engineer') const personTwo = createPerson('Gred', 24, 'Doctor')
2. 构造函数模式
(1)与工厂模式相比构造函数模式
- 没有显示地创建对象
- 直接将属性和方法赋值给了this对象
- 没有return语句
- 区别于非构造函数,构造函数以大写字母开头
(2)要创建Person的新实例,必须使用new操作符。
以这种方式调用构造函数实际上会经历以下4个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数的代码(为这个新对象添加属性)
- 返回新对象
function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.sayName = function() {alert(this.name)}; } const personOne = new Person('lee', 29, 'Software Engineer') const personTwo = new Person('Gred', 24, 'Doctor')
(3)personOne和personTwo分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性,该属性指向Person
console.log(personOne.constructor == Person) // true console.log(personTwo.constructor == Person) // true
(4)以上例子中创建的所有对象既是Object的实例,同时也是Person的实例,这一点通过instanceof操作符可以得到验证。
console.log(personOne instanceof Person) // true console.log(personOne instanceof Object) // true console.log(personTwo instanceof Person) // true console.log(personTwo instanceof Object) // true
(5)构造函数毕竟也是函数,不存在定义构造函数的特殊语法。任何函数,只要通过new操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过new操作符来调用,那它跟普通函数也不会有什么两样。
// 当作构造函数使用 const person = new Person('lee', 29, 'Software Engineer'); person.sayName(); // 'lee'// 作为普通函数调用 Person('Gred', 24, 'Doctor') // 添加到window window.sayName(); // 'Gred'// 在另外一个对象的作用域中调用 const o = new Object(); Person.call(o, 'Alice', 27, 'Nurse'); o.sayName(); // 'Alice'
缺点:每个方法都要在每个实例上重新创建一遍。
解决方法:把函数转移到构造函数外。
function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.sayName = sayName } function sayName() {alert(this.name)}; const personOne = new Person('lee', 29, 'Software Engineer') const personTwo = new Person('Gred', 24, 'Doctor')
如上,两个实例的sayName共享了一个全局的sayName方法。解决了2个函数做同一件事的问题。但是新问题又来了:
在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实
如果对象需要定义很多方法,那么就要定义很多全局函数,导致我们这个自定义的引用类型丝毫没有封装性可言。
3. 原型模式
(1) 针对以上构造函数的痛点,原型模式可以解决这些问题。
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的作用是包含可以由特定类型的所有实例共享的属性和方法。prototype就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处就是不用在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
function Person() {} Person.prototype.name = 'lee'; Person.prototype.age = 29; Person.prototype.job = 'Software Engineer'; Person.prototype.sayName = function() {alert(this.name) }; const personOne = new Person(); personOne.sayName(); // 'lee' const personTwo = new Person(); personTwo.sayName(); // 'lee' console.log(personOne.sayName == personTwo.sayName); // true//简写 function Person(){} Person.prototype = {constructor: Person,name: 'lee',age: 29,job: 'Software Engineer',sayName: function(){alert(this.name)} };
(2)默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针。如上例子,Person.prototype.constructor指向Person。
Person.prototype.constructor === Person // true
(3)当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。这个内部属性[ [ Prototype ] ],虽然无法访问到。但是可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。如果[ [ Prototype ] ]指向调用isPrototypeOf()方法的对象(Person.prototype),那么这个方法就返回true。
console.log(Person.prototype.isPrototypeOf(personOne)); // true console.log(Person.prototype.isPrototypeOf(personTwo)); // true
(4)Object.getPrototypeOf() 这个方法返回[ [ Prototype ] ]的值
console.log(Object.getPrototypeOf(personOne) == Person.prototype); // true console.log(Object.getPrototypeOf(personOne).name); // 'lee' console.log(Object.getPrototypeOf(personTwo) == Person.prototype); // true console.log(Object.getPrototypeOf(personTwo).name); // 'lee'
(5)使用delete可以删除实例中的属性
personOne.name = 'Alice'; console.log(personOne.name) // 'Alice' 来自实例 console.log(personTwo.name) // 'lee' 来自原型 delete personOne.name; console.log(personOne.name) // 'lee' 来自原型
(6)hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中。如果该属性存在于实例中,则返回true。
personOne.name = 'Alice'; console.log(personOne.hasOwnProperty('name')) // true console.log(personTwo.hasOwnProperty('name')) // false
(7)in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
personOne.name = 'Alice'; console.log('name' in personOne) // true name在实例中 console.log('name' in personTwo) // true name在原型中
(8)getOwnPropertyNames()方法得到所有实例属性,无论它是否可枚举。
const keys = Object.getOwnPropertyNames(Person.prototype); console.log(keys); // ['constructor','name','age','job','sayName']
(9)可以随时给原型添加属性和方法,但是如果是重写整个原型对象,就相当于把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。
function Person(){} const friend = new Person(); Person.prototype = {name: 'lee',age: 29,job: 'Software Engineer',sayName: function(){alert(this.name)} }; friend.sayName(); // error //因为这时的friend指向的是以前的Person,而以前的是没有sayName方法的,所以报错。 //而且这里旧的原型对象和新的原型对象的指针都指向Person
缺点:
(1)所有实例在默认情况下都将取得相同的属性值。(上面例子中定义的name,age等)(2)原型中存在引用类型,会导致每一个实例共享这个引用类型。如下例子:每一个实例中的friends会因为其中一个实例的修改,都共享了这个修改后的结果。
function Person(){} Person.prototype = {constructor: Person,name: 'lee',age: 29,friends: ['Jack', 'Bob'],job: 'Software Engineer',sayName: function(){alert(this.name)} }; const personOne = new Person(); const personTwo = new Person(); personOne.friends.push('Ivan'); console.log(personOne.friends); // ['Jack', 'Bob', 'Ivan'] console.log(personTwo.friends); // ['Jack', 'Bob', 'Ivan'] console.log(personOne.friends === personTwo.friends); // true
4. 组合使用构造函数模式和原型模式
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。
function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.friends = ['Jack', 'Bob']; } Person.prototype = {constructor: Person,sayName: function() {alert(this.name);}} const personOne = new Person('lee', 29, 'Software Engineer') const personTwo = new Person('Gred', 24, 'Doctor') personOne.friends.push('Van'); console.log(personOne.friends); // ['Jack', 'Bob', 'Ivan'] console.log(personTwo.friends); // ['Jack', 'Bob'] console.log(personOne.friends === personTwo.friends); // false console.log(personOne.sayName === personTwo.sayName); // true
相关文章:
对象创建的4种模式
1. 工厂模式 这种模式抽象了创建具体对象的过程,用函数来封装以特定接口创建对象的细节 缺点:没有解决对象识别的问题(即怎样知道一个对象的类型) function createPerson(name, age, job) {var o new Object();o.name name;o.ag…...
如何判断 是否 需要 CSS 中的媒体查询
以下是一些常见的使用媒体查询的场景: 响应式布局:当设备的屏幕尺寸变化时,我们可以使用媒体查询来调整布局,以适应不同的屏幕尺寸。 设备特性适配:我们可以使用媒体查询来检测设备的特性,如设备方向、分辨…...

设计模式-装饰器模式(结构型)
装饰器模式 装饰器模式是一种结构模式,通过装饰器模式可以在不改变原有类结构的情况下向一个新对象添加新功能,是现有类的包装。 图解 角色 抽象组件:定义组件的抽象方法具体组件:实现组件的抽象方法抽象装饰器:实现…...

升级HarmonyOS 4.2,开启健康生活篇章
夏日来临,华为智能手表携 HarmonyOS 4.2 版本邀您体验,它不仅可以作为时尚单品搭配夏日绚丽服饰,还能充当你的健康管家,从而更了解自己的身体,开启智能健康生活篇章。 高血糖风险评估优化,健康监测更精准 …...
给gRPC增加负载均衡功能
在现代的分布式系统中,负载均衡是确保服务高可用性和性能的关键技术之一。而gRPC作为一种高性能的RPC框架,自然也支持负载均衡功能。本文将探讨如何为gRPC服务增加负载均衡功能,从而提高系统的性能和可扩展性。 什么是负载均衡? …...

【优选算法】详解target类求和问题(附总结)
目录 1.两数求和 题目: 算法思路: 代码: 2.!!!三数之和 题目 算法思路: 代码: 3.四数字和 题目: 算法思路: 代码: 总结&易错点&…...

【数据结构】图论入门
引入 数据的逻辑结构: 集合:数据元素间除“同属于一个集合”外,无其他关系线性结构:一个对一个,例如:线性表、栈、队列树形结构:一个对多个,例如:树图形结构࿱…...
11_1 Linux NFS服务与触发挂载autofs
11_1 Linux NFS服务与触发挂载服务 文章目录 11_1 Linux NFS服务与触发挂载服务[toc]1. NFS服务基础1.1 示例 2. 触发挂载autofs2.1 触发挂载基础2.2 触发挂载进阶autofs与NFS 文件共享服务:scp、FTP、web(httpd)、NFS 1. NFS服务基础 Netwo…...

开发uniapp 小程序时遇到的问题
1、【微信开发者工具报错】routeDone with a webviewId XXX that is not the current page 解决方案: 在app.json 中添加 “lazyCodeLoading”: “requiredComponents” uniapp的话加到manifest.json下的mp-weixin 外部链接文章:解决方案文章1 解决方案文章2 &qu…...

怎样快速获取Vmware VCP 证书,线上考试,voucher报名优惠
之前考一个VCP证书,要花大一万的费用,可贵了,考试费不贵,贵就贵在培训费,要拿到证书,必须交培训费,即使vmware你玩的很溜,不需要再培训了,但是一笔贵到肉疼的培训费你得拿…...
LeetCode 1141, 134, 142
目录 1141. 查询近30天活跃用户数题目链接表要求知识点思路代码 134. 加油站题目链接标签普通版思路代码 简化版思路代码 142. 环形链表 II题目链接标签思路代码 1141. 查询近30天活跃用户数 题目链接 1141. 查询近30天活跃用户数 表 表Activity的字段为user_id,…...
华为FPGA工程师面试题
FPGA工程师面试会涉及多个方面,包括基础知识、项目经验、编程能力、硬件调试和分析等。以下是一些必问的面试题: 基础知识题: 请解释FPGA的基本组成和工作原理。描述FPGA中的可编程互联资源以及它们在构建复杂数字电路中的作用。请解释嵌入式多用途块(如BRAM、DSP slices、…...

Windows11上安装docker(WSL2后端)和使用docker安装MySQL和达梦数据库
Windows11上安装docker(WSL2后端)和使用docker安装MySQL和达梦数据库 1. 操作系统环境2. 首先安装wsl2.1 关于wsl2.2 安装wsl2.3 查看可用的wsl2.4 安装ubuntu-22.042.5 查看、启动ubuntu-22.04应用2.6 上面安装开了daili2.7 wsl的更多参考 3. 下载Docke…...

UnityXR Interactable Toolkit如何实现Climb爬梯子
前言 在VR中,通常会有一些交互需要我们做爬梯子,爬墙的操作,之前用VRTK3时,里面是还有这个Demo的,最近看XRI,发现也除了一个爬的示例,今天我们就来讲解一下 如何在Unity中使用XR Interaction Toolkit实现爬行(Climb)操作 环境配置 步骤 1:设置XR环境 确保你的Uni…...

sqli-labs 靶场 less-11~14 第十一关、第十二关、第十三关、第十四关详解:联合注入、错误注入
SQLi-Labs是一个用于学习和练习SQL注入漏洞的开源应用程序。通过它,我们可以学习如何识别和利用不同类型的SQL注入漏洞,并了解如何修复和防范这些漏洞。Less 11 SQLI DUMB SERIES-11判断注入点 尝试在用户名这个字段实施注入,且试出SQL语句闭合方式为单…...
国内外网络安全现状分析
一、国内网络安全现状 1.1 国内网络安全威胁 国内的网络安全威胁主要表现在以下几个方面: 恶意软件:包括计算机病毒、蠕虫、木马和间谍软件等,它们能感染计算机系统、窃取敏感信息或破坏系统功能。网络钓鱼:通过伪装成可信任的…...

vscode copilot git commit 生成效果太差,用其他模型替换
问题 众所周知,copilot git commit 就像在随机生成 git commit 这种较为复杂的内容还是交给大模型做比较合适 方法 刚好,gitlens 最近开发了 AI commit的功能,其提供配置url api可以实现自定义模型 gitlens 只有3种模型可用:…...

计算机毕业设计hadoop+spark+hive舆情分析系统 微博数据分析可视化大屏 微博情感分析 微博爬虫 微博大数据 微博推荐系统 微博预测系统
本 科 毕 业 论 文 论文题目:基于Hadoop的热点舆情数据分析与可视化 姓名: 金泓羽 学号: 20200804050115 导师: 关英 职称&…...

【MySQL】(基础篇二) —— MySQL初始用
MySQL初始用 目录 MySQL初始用基本语法约定选择数据库查看数据库和表其它的SHOW 在Navicat中,大部分数据库管理相关的操作都可以通过图形界面完成,这个很简单,大家可以自行探索。虽然Navicat等图形化数据库管理工具为操作和管理数据库提供了非…...

计算机网络 期末复习(谢希仁版本)第4章
路由器:查找转发表,转发分组。 IP网的意义:当互联网上的主机进行通信时,就好像在一个网络上通信一样,看不见互连的各具体的网络异构细节。如果在这种覆盖全球的 IP 网的上层使用 TCP 协议,那么就…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...