前端开发之原型模式

news/2024/9/20 6:02:49 标签: 原型模式, 设计模式, 前端

介绍

原型模式本质就是借用一个已有的实例做原型,在这原型基础上快速复制出一个和原型一样的一个对象。

class CloneDemo {
    name = 'clone demo'
    clone(): CloneDemo {
        return  new CloneDemo()
    }
}

原型原型链

  1. 函数(class)都有显示原型 prototype
  2. 对象都有隐式原型__proto__
  3. 对象__proto__指向其构造函数的 prototype

原型链:当试图访问一个对象的属性或方法时,如果对象本身没有定义这个属性或方法,JavaScript引擎就会沿着这个对象的原型链向上查找,直到找到或者到达原型链的末端。

class 是 function 的语法糖

class Foo {}
const f1 = new Foo()
console.log(f1.__proto__ === Foo.prototype) // true

 场景

const obj = {
  foo() {
    console.log("foo");
  },
};
const obj2 = Object.create(obj);
obj2.foo(); // foo
console.log(obj2.__proto__ === obj); // true

Object.create(null)、Object.create({})和 {} 的区别?

const obj1 = Object.create(null)
console.log("obj1", obj1)

const obj2 = {}
console.log("obj2", obj2)

const obj3 = Object.create(Object.prototype)
console.log("obj3", obj3)

const obj4 = Object.create({})
console.log("obj4", obj4)

如上图结果:

  1. Object.create(null) 创建的对象是一个空对象,在该对象上没有继承 Object.prototype 原型链上的属性或者方法。也就是没有任何属性,显示 No properties 。
  2. Object.create(Object.prototype) 和 {} 创建的一模一样。
  3. Object.create({}) 相比于 {} 多了一层 proto 嵌套。

对象属性描述符

const obj = { x: 100 }; // 各项属性默认都是 true, 但是通过 defineProperty 定义的各项属性都是false

const gopd = Object.getOwnPropertyDescriptor(obj, "x");
console.log(gopd); // {value: 100, writable: true, enumerable: true, configurable: true}    

Object.defineProperty(obj, "y", {
  value: 200,
  writable: false,
});
console.log(obj); // {x: 100, y: 200}
obj.y = 201;
console.log(obj.y); // 200

(1)value

它是用来定义属性值,如果没有value,则看不到对象属性值,但可以通过get set 来操作属性值。

const obj = { x: 100 };

let y = 200;
Object.defineProperty(obj, "y", {
  get() {
    return y;
  },
  set(newValue) {
    y = newValue;
  },
});
console.log(obj); // {x: 100} 这里没有 y
console.log(obj.y); // 200 但是这里又能打印出 y
obj.y = 201;
console.log(obj.y); // 201
console.log(obj); // {x: 100} 还是没有 y
const gopd = Object.getOwnPropertyDescriptor(obj, "y");
console.log(gopd); // {enumerable: false, configurable: false, get: ƒ, set: ƒ} 确实没有 value,所以没有显示 y

(2)configurable

是否可以 delete 删除,并重新定义

是否可以修改其他属性描述符

是否可以修改get set

const obj = { x: 100 };

Object.defineProperty(obj, "y", {
  value: 200,
    configurable: false
});

Object.defineProperty(obj, "z", {
  value: 300,
    configurable: true
});
console.log(obj) // {x: 100, y: 200, z: 300}
console.log(delete obj.y) // false

// Object.defineProperty(obj, "y", {
//     value: 201,
//     configurable: false
// });
// Uncaught TypeError: Cannot redefine property: y

Object.defineProperty(obj, "z", {
    value: 301,
    configurable: true
});
console.log(obj) // {x: 100, y: 200, z: 301}

(3)writable

属性值是否可被修改。对比Object.freeze()"冻结"、Object.seal()"密封"

const obj = { x: 100 };
Object.defineProperty(obj, "y", {
  value: 200,
  writable: false,
});
obj.x = 101;
console.log(obj); // {x: 101, y: 200}
obj.y = 201;
console.log(obj); // {x: 101, y: 200} 无法修改 y

// Object.freeze() "冻结":现有属性不可被修改;2.不可添加新属性
const obj = { x: 100, y: 200 };
Object.freeze(obj);
console.log(Object.getOwnPropertyDescriptor(obj, 'x')) // {value: 100, writable: false, enumerable: true, configurable: false}
console.log(Object.isFrozen(obj)); // true
obj.x = 101; // Uncaught TypeError: Cannot assign to read only property 'x' of object '#<Object>'
obj.z = 300; // Uncaught TypeError: Cannot add property z, object is not extensible

// Object.seal()"密封":1.现有属性可以被修改;2.不可添加新属性
const obj = { x: 100, y: 200 };
Object.seal(obj);
obj.x = 101;
console.log(obj.x); // 101 修改成功
console.log(Object.getOwnPropertyDescriptor(obj, 'x')) // {value: 101, writable: true, enumerable: true, configurable: false}
console.log(Object.isSealed(obj)); // true
obj.z = 300; // Uncaught TypeError: Cannot add property z, object is not extensible

(4)enumerable

是否可以通过for in 遍历。

const obj = { x: 100 };
Object.defineProperty(obj, "y", {
  value: 200,
  enumerable: false,
});
Object.defineProperty(obj, "z", {
  value: 300,
  enumerable: true,
});
for (const key in obj) {
  console.log(key);
}
// x z
console.log("x" in obj); // true
console.log("y" in obj); // true
console.log("z" in obj); // true

原型属性的 enumerable:在以前,for in 可以遍历出原型属性。现在全根据 enumerable 来遍历。为什么没有原型属性了呢?

console.log(Object.getOwnPropertyDescriptor(obj.__proto__, 'toString')) 
// {writable: true, enumerable: false, configurable: true, value: ƒ}

可见 enumerable 是 false,所以再用for in 遍历就遍历不出来了。之前是怎么做的呢?之前有一个方法是 hasOwnProperty 来判断是否原型属性。

console.log(obj.hasOwnProperty("x")); // true
console.log(obj.hasOwnProperty("toString")); // false

如何遍历Symbol 属性?

const a = Symbol("a");
const obj = { [a]: 10, b: 20 };

console.log(Object.getOwnPropertyDescriptor(obj, a)); // {value: 10, writable: true, enumerable: true, configurable: true}

for (const key in obj) {
  console.log(key);
}
// b  说明 for in 的限制不光有 enumerable,还有 Symbol 类型。
// 那么如何把Symbol遍历出来呢?
console.log(Object.keys(obj)); // ['b']
console.log(Object.getOwnPropertyNames(obj)); // ['b']
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(a)]
console.log(Reflect.ownKeys(obj)); // ['b', Symbol(a)]

http://www.niftyadmin.cn/n/5666687.html

相关文章

【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(上)

文章目录 前言一、ArkTS基本介绍1、 ArkTS组成2、组件参数和属性2.1、区分参数和属性的含义2.2、父子组件嵌套 二、装饰器语法1.State2.Prop3.Link4.Watch5.Provide和Consume6.Observed和ObjectLink代码示例&#xff1a;示例1&#xff1a;&#xff08;不使用Observed和ObjectLi…

GSM安全特性

GSM安全特性&#xff0c;具体内容如下&#xff1a; 1. 安全特性&#xff1a; GSM的安全方面在3GPP TS 42.009 [4]和3GPP TS 43.020 [11]的规范参考文献中有描述。本条款提供了SIM卡支持的安全特性信息&#xff0c;以实现以下功能&#xff1a; 对网络进行用户身份认证&#x…

虚拟机安装nginx需要注意的一些事项

1. sudo systemctl status firewalld ------检查虚拟机防火墙是否在运行 2.sudo systemctl stop firewalld ---------- 停止防火墙的运行 我的虚拟机中nginx的安装位置在 cd /usr/local/nginx-1.20.2/sbin/nginx 启动nginx服务命令&#xff1a;./n…

【Git原理与使用】多人协作与开发模型(2)

目录 一、多人协作 (一)多人协作一 1、情景&#xff1a; 2、 origin/master 3、git branch 4、远程链接 5、总结 (二)多人协作二 1、引言 2、情景 3、流程 4、解决方法 二、企业级开发模型 1、DevOps背景 2、DevOps是什么 3、DevCps与git的关系 4、系统开发环境 5、Git分支设计…

涛思数据库安装和卸载

安装 cd opt/taos/TDengine-server-2.4.0.5 sudo ./install.sh 启动taos​ 安装后&#xff0c;请使用 systemctl 命令来启动 TDengine 的服务进程 systemctl start taosd检查服务是否正常工作&#xff1a; systemctl status taosd 升级 3.0 版在之前版本的基础上&#x…

PostgreSQL 向量数据存储指南

引言 在当今的数字化时代&#xff0c;数据存储的方式和技术正变得越来越复杂和多样化。随着机器学习和数据科学的发展&#xff0c;向量数据的存储和管理变得尤为重要。本文将详细介绍如何使用 Java 和 PostgreSQL 数据库来存储向量数据&#xff0c;探索其应用场景、优势以及具…

Go 并发模式:扩展与聚合的高效并行

当你搭建好一个管道系统后,数据在各个阶段之间顺畅地流动,并根据你设定的操作逐步转换。这一切看起来像是一条美丽的溪流,然而,为什么有时候这个过程会如此缓慢呢? 在处理数据时,某些阶段可能会非常耗时,导致上游的阶段被阻塞,无法继续处理数据。这不仅影响了管道的整…

Log4j2—漏洞分析(CVE-2021-44228)

文章目录 Log4j2漏洞原理漏洞根因调用链源码分析调用链总结 漏洞复现dnsrmi Log4j2漏洞原理 前排提醒&#xff1a;本篇文章基于我另外一篇总结的JNDI注入后写的&#xff0c;建议先看该文章进行简单了解JNDI注入&#xff1a; https://blog.csdn.net/weixin_60521036/article/de…