对象创建的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 协议,那么就…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
