ES6 class类中定义私有变量
ES6 class类中定义私有变量
class类的不足
看起来, es6 中 class 的出现拉近了 JS 和传统 OOP 语言的距离。但是,它仅仅是一个语法糖罢了,不能实现传统 OOP 语言一样的功能。在其中,比较大的一个痛点就是私有变量问题。
何为私有变量?私有变量就是只能在类内部访问的变量,外部无法访问的变量。在开发中,很多变量或方法你不想其他人访问,可以定义为私有变量,防止被其他人使用。在 Java 中,可以使用 private 实现私有变量,但是可惜的是, JS 中并没有该功能。
来看下下面这个代码:
class A {
constructor(x) {
this.x = x
}
// 想要通过该方法来暴露x
showX() {
return this.x
}
}
let a = new A(1)
// 直接访问x成功
a.x // 1
可以看到,虽然本意是通过方法 showX 来暴露 x 的值,但是可以直接通过 a. x 来直接访问 x 的值。
很明显,这影响了代码的封装性。要知道,这些属性都是可以使用 for... in 来遍历出来的。
所以,实现 class 的私有变量功能是很有必要的。
实现 class 私有变量
虽然, class 本身没有提供私有变量的功能,但是,我们可以通过通过一些方式来实现类似于私有变量的功能。
约定命名
首先,是目前使用最广的方式:约定命名。
该方式很简单,就是团队自行约定一种代表着私有变量的命名方式,一般是在私有变量的名称前加上一个下划线。代码如下:
class A {
constructor(x) {
// _x 是一个私有变量
this._x = x
}
showX() {
return this._x
}
}
let a = new A(1)
// _x 依然可以被使用
a._x // 1
a.showX() //1
可以发现,该方法最大的优点是简单、方便,所以很多团队都采用了这种方式。
但是,该方式并没有从本质上解决问题,如果使用 for... in 依然可以遍历出所谓的私有变量,可以说是治标不治本。
不过,该方式有一点值得肯定,那就是通过约定规范来方便他人阅读代码。
闭包
闭包在很多时候被拿来解决模块化问题,显而易见,私有变量本质上也是一种模块化问题,所以,我们也可以使用闭包来解决私有变量的问题。
我们在构造函数中定义一个局部变量,然后通过方法引用,该变量就成为了真正的私有变量。
class A {
constructor(x) {
let _x = x
this.showX = function() {
return _x
}
}
}
let a = new A(1)
// 无法访问
a._x // undefined
// 可以访问
a.showX() // 1
该方法最大的优点就是从本质解决了私有变量的问题。
但是有个很大的问题,在这种情况下,引用私有变量的方法不能定义在原型链上,只能定义在构造函数中,也就是实例上。这导致了两个缺点:
增加了额外的性能开销
构造函数中包含了方法,较为臃肿,对后续维护造成了一定的麻烦
进阶版闭包方式
既然在构造函数内部定义闭包那么麻烦,那我放在 class 外面不就可以了吗?
- 我们可以通过 IIFE (立即执行函数表达式) 建立一个闭包
- 在其中建立一个变量以及 class ,通过 class 引用变量实现私有变量。
代码如下:
// 利用闭包生成IIFE,返回类A
const A = (function() {
// 定义私有变量_x
let _x
class A {
constructor(x) {
// 初始化私有变量_x
_x = x
}
showX() {
return _x
}
}
return A
})()
let a = new A(1)
// 无法访问
a._x // undefined
// 可以访问
a.showX() //1
可以发现,该方法完美解决了之前闭包的问题,只不过写法相对复杂一些,另外,还需要额外创建 IIFE ,有一点额外的性能开销。
- 注:该方式也可以不使用 IIFE ,可以直接将私有变量置于全局,但是这不利于封装性。
Symbol
这种方式利用的是 Symbol 的唯一性—— 敌人最大的优势是知道我方key值,我把key值弄成唯一的,敌人不知道我的key值,不就无法访问了吗? (人质是这次任务的关键,当敌人不再拥有人质时,任务也就完成了)
代码如下:
// A模块
const x = Symbol('x')
export default class A {
constructor(a) {
// 利用symbol声明私有变量
this[x] = a
}
showX() {
return this[x]
}
}
// B模块
import A from "A模块"
const a = new A(1)
// 1. 第一种方式
a[_x] // 报错 Uncaught ReferenceError: _x is not defined
// 2. 第二种方式
// 自行定义一个相同的Symbol
const x = Symbol('x')
a[x] // 无法访问,undefined
// 3. 第三种方式,可以访问(正解)
a.showX() //1
ES6 class类中定义私有变量的更多相关文章
- Python类中的 私有变量和私有方法
默认情况下,Python中的成员函数和成员变量都是公开的(public),在python中没有类似public,private等关键词来修饰成员函数和成员变量.在python中定义私有变量只需要在变量 ...
- MFC 如何在一个类中使用在其他类中定义的变量或函数
[声明:本文的知识点来源于网络,参考网址:https://blog.csdn.net/bill_ming/article/details/7407848] [以下三种方法亲测有效,可以根据具体情况来选 ...
- 第7.10节 Python类中的实例变量定义与使用
一. 引言 在前面章节已经引入介绍了类变量和实例变量,类体中定义的变量为类变量,默认属于类本身,实例变量是实例方法中定义的self对象的变量,对于每个实例都是独有数据,而类变量是该类所有实例共享 ...
- JavaScript中是如何定义私有变量的
前言 JavaScript并不像别的语言,能使用关键字来声明私有变量. 我了解的JavaScript能用来声明私有变量的方式有两种,一种是使用闭包,一种是使用WeakMap. 闭包 闭包的描述有很多种 ...
- OC中的私有变量和description
.OC中的私有变量 在类的实现即.m @implementation中也可以声明成员变量,但是因为在其他文件中通常都只 是包含头文件而不会包含实现文件,所以在.m文件中声明的成员变量是@private ...
- python中的私有变量
class Test1: def f1(self): self.name ="张三" self.__age = 20 #使用名称变形实现私有变量 print(self.name) ...
- C++ 类中的静态成员变量,静态成员函数
//类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...
- C++类中的静态成员变量与静态成员函数
最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态 ...
- Java中主类中定义方法加static和不加static的区别
Java中主类中定义方法加static和不加static的区别(前者可以省略类名直接在主方法调用(类名.方法),后者必须先实例化后用实例调用) 知识点:1.Getter and Setter 的应用 ...
随机推荐
- Python的输入输出的应用
输入输出主要掌握print()和input()两个函数的应用. #print函数用于控制台输出 print('I love Python.','So I want to learn it.','I b ...
- Android框架式编程之ViewModel
一.ViewModel介绍 ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据.ViewModel中数据会一直存活即使 Activity Configuration发生变 ...
- c#串口通信并处理接收的多个参数
最近摸索做个上位机,简单记录一下关键的几个部分 c#做串口通信主要使用的是System.IO.Ports类,其实还是十分方便的 最终效果如下: 千万不要忘记了下面这个 填写串口相关配置 我们可以通过G ...
- SQL Server如何找出一个表包含的页信息(Page)
在SQL Server中,如何找到一张表或某个索引拥有那些页面(page)呢? 有时候,我们在分析和研究(例如,死锁分析)的时候还真有这样的需求,那么如何做呢? SQL Server 2012提供了一 ...
- s3c2440裸机-内存控制器(四、SDRAM原理-cpu是如何访问sdram的)
1.SDRAM原理 black (1)SDRAM内部存储结构: (2)再看看与2440连接的SDRAM原理图: sdram引脚说明: A0-A12:地址总线 D0-D15:数据总线(位宽16,2片级联 ...
- Web安全测试学习笔记-DVWA-SQL注入-2
接上一篇SQL注入的学习笔记,上一篇我通过报错信息得知后台数据库是MySQL(这个信息非常重要~),然后通过SQL注入拿到了用户表的所有行,其实我们还可以通过MySQL的特性来拿更多的信息. 1. 获 ...
- 高并发 Nginx+Lua OpenResty系列(11)——流量复制/AB测试/协程
流量复制 在实际开发中经常涉及到项目的升级,而该升级不能简单的上线就完事了,需要验证该升级是否兼容老的上线,因此可能需要并行运行两个项目一段时间进行数据比对和校验,待没问题后再进行上线.这其实就需要进 ...
- Java 添加Word页眉、页脚
本篇文章将介绍通过java程序来添加Word页眉页脚的方法.鉴于在不同文档中,对页眉页脚的操作要求不同,文章将分别从以下几种情况来阐述: 1.添加页眉页脚 添加图片到页眉 添加文本到页眉 添加页码 2 ...
- 保护模式中的PDE与PTE
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 保护模式中的PDE与PTE 1. PDE与PTE的认知 我们在上一 ...
- 基于STM32F429,Cubemx的SAI音频播放实验
书接上文:https://www.cnblogs.com/feiniaoliangtiangao/p/11060674.html 和 https://www.cnblogs.com/feiniaoli ...