前言

在阅读 《ECMAScript 6 入门》的时候,零散的看到有私有变量的实现,所以在此总结一篇。

1. 约定

实现

class Example {
constructor() {
this._private = 'private';
}
getName() {
return this._private
}
} var ex = new Example(); console.log(ex.getName()); // private
console.log(ex._private); // private

优点

  1. 写法简单
  2. 调试方便
  3. 兼容性好

缺点

  1. 外部可以访问和修改
  2. 语言没有配合的机制,如 for in 语句会将所有属性枚举出来
  3. 命名冲突

2. 闭包

实现一

/**
* 实现一
*/
class Example {
constructor() {
var _private = '';
_private = 'private';
this.getName = function() {return _private}
}
} var ex = new Example(); console.log(ex.getName()); // private
console.log(ex._private); // undefined

优点

  1. 无命名冲突
  2. 外部无法访问和修改

缺点

  1. constructor 的逻辑变得复杂。构造函数应该只做对象初始化的事情,现在为了实现私有变量,必须包含部分方法的实现,代码组织上略不清晰。
  2. 方法存在于实例,而非原型上,子类也无法使用 super 调用
  3. 构建增加一点点开销

实现二

/**
* 实现二
*/
const Example = (function() {
var _private = ''; class Example {
constructor() {
_private = 'private';
}
getName() {
return _private;
}
} return Example; })(); var ex = new Example(); console.log(ex.getName()); // private
console.log(ex._private); // undefined

优点

  1. 无命名冲突
  2. 外部无法访问和修改

缺点

  1. 写法有一点复杂
  2. 构建增加一点点开销

3. Symbol

实现

const Example = (function() {
var _private = Symbol('private'); class Example {
constructor() {
this[_private] = 'private';
}
getName() {
return this[_private];
}
} return Example;
})(); var ex = new Example(); console.log(ex.getName()); // private
console.log(ex.name); // undefined

优点

  1. 无命名冲突
  2. 外部无法访问和修改
  3. 无性能损失

缺点

  1. 写法稍微复杂
  2. 兼容性也还好

4. WeakMap

实现

/**
* 实现一
*/
const _private = new WeakMap(); class Example {
constructor() {
_private.set(this, 'private');
}
getName() {
return _private.get(this);
}
} var ex = new Example(); console.log(ex.getName()); // private
console.log(ex.name); // undefined

如果这样写,你可能觉得封装性不够,你也可以这样写:

/**
* 实现二
*/
const Example = (function() {
var _private = new WeakMap(); // 私有成员存储容器 class Example {
constructor() {
_private.set(this, 'private');
}
getName() {
return _private.get(this);
}
} return Example;
})(); var ex = new Example(); console.log(ex.getName()); // private
console.log(ex.name); // undefined

优点

  1. 无命名冲突
  2. 外部无法访问和修改

缺点

  1. 写法比较麻烦
  2. 兼容性有点问题
  3. 有一定性能代价

5. 最新提案

class Point {
#x;
#y; constructor(x, y) {
this.#x = x;
this.#y = y;
} equals(point) {
return this.#x === point.#x && this.#y === point.#y;
}
}

那么为什么不直接使用 private 字段呢?比如说这样:

class Foo {
private value; equals(foo) {
return this.value === foo.value;
}
}

简单点来说,就是嫌麻烦,当然也有性能上的考虑……

举个例子,如果我们不使用 #,而是使用 private 关键字:

class Foo {
private value = '1'; equals(foo) {
return this.value === foo.value;
}
} var foo1 = new Foo();
var foo2 = new Foo(); console.log(foo1.equals(foo2));

在这里我们新建了两个实例,然后将 foo2 作为参数传入了 foo1 的实例方法中。

那么我们可以获取 foo2.value 的值吗?如果我们直接 foo2.value 肯定是获取不到值的,毕竟是私有变量,可是 equals 是 Foo 的一个类方法,那么可以获取到的吗?

答案是可以的。

其实这点在其他语言,比如说 Java 和 C++ 中也是一样的,类的成员函数中可以访问同类型实例的私有变量,这是因为私有是为了实现“对外”的信息隐藏,在类自己内部,没有必要禁止私有变量的访问,你也可以理解为私有变量的限制是以类为单位,而不是以对象为单位,此外这样做也可以为使用者带来便利。

既然获取值是可以的,那么打印的结果应该为 true,但是如果我们传入的值不是 Foo 的实例,而是一个其他对象呢?

var foo1 = new Foo();

console.log(foo1.equals({
value: 2
}));

当然这里代码也是可以正常运行的,但是对于编译器来说,就有一点麻烦了,因为编译器不知道 value 到底是 foo 的正常属性还是私有属性,所以编译器需要做判断,先判断 foo 是不是 Foo 的实例,然后再接着获取值。

这也意味着每次属性访问都需要做这样一个判断,而引擎已经围绕属性访问做了高度优化,懒得改,而且还降低速度。

不过除了这个工作之外,还会有一些其他的内容需要考虑,比如说:

  1. 你必须将私有的 key 编码进每个词法环境
  2. for in 可以遍历这些属性吗?
  3. 私有属性和正常属性同名的时候,谁会屏蔽谁?
  4. 怎么防止私有属性的名称不被探测出来。

关于使用 # 而不使用 private 更多的讨论可以参考这个 Issue。

当然这些问题都可以被解决啦,就是麻烦了点。

而如果你选择 #,实现的方式将跟 JavaScript 对象属性完全没有关系,将会使用 private slots 的方式以及使用一个新的 slot 查找语法,总之就是会比 private 的实现方式简单很多。

原文链接
本文为云栖社区原创内容,未经允许不得转载。

ES6 系列之私有变量的实现的更多相关文章

  1. ES6系列_3之变量的解构赋值

    ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构. 解构有三种类型: 1.数组的解构赋值 (1)简单的数组解构 以前,我们给变量赋值是直接单个指定值,比如: let a=0; ...

  2. es6系列-变量声明

    es6系列所有文章都是阅读阮一峰老师的<ES6标准入门>(第2版)所做的读书笔记.方便日后查阅相关基础知识. git地址: https://github.com/rainnaZR/es6- ...

  3. ES6 class类中定义私有变量

    ES6 class类中定义私有变量 class类的不足 看起来, es6 中 class 的出现拉近了 JS 和传统 OOP 语言的距离.但是,它仅仅是一个语法糖罢了,不能实现传统 OOP 语言一样的 ...

  4. 【原】iOS动态性(二):运行时runtime初探(强制获取并修改私有变量,强制增加及修改私有方法等)

    OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法.利用runtime机制让我们可以在程序运行时动态修改类.对象中的所有属性.方法,就算是私有方法以及私有属性都是可以动 ...

  5. [js高手之路] es6系列教程 - 对象功能扩展详解

    第一:字面量对象的方法,支持缩写形式 //es6之前,这么写 var User = { name : 'ghostwu', showName : function(){ return this.nam ...

  6. iOS动态性 运行时runtime初探(强制获取并修改私有变量,强制增加及修改私有方法等)

    借助前辈的力量综合一下资料. OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法.利用runtime机制让我们可以在程序运行时动态修改类.对象中的所有属性.方法,就算是 ...

  7. [js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解

    接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般 ...

  8. es5 温故而知新 创建私有成员、私有变量、特权变量的方法

    其实js是不支持私有变量的.哪怕到es6的class语法.虽然有许多变相的方式.但非常冗余而不推崇. 这里介绍的实际上也不是class语法,而是普通的函数,并且利用IIFE(闭包)的方式来实现私有. ...

  9. 浅谈class私有变量

    class 的前世今生 在 es6 之前,虽然 JS 和 Java 同样都是 OOP (面向对象)语言,但是在 JS 中,只有对象而没有类的概念. 在 JS 中,生成实例对象的传统方法是通过构造函数, ...

随机推荐

  1. Linux如何挂载U盘

    1,以root用户登陆   先加载USB模块 modprobe usb-storage   用fdisk -l 看看U盘的设备   假如U盘是sda1 2,确定在 目录 /mnt 下建立了 文件夹 / ...

  2. ASP.NET代码调用SQL Server带DateTime类型参数的存储过程抛出异常问题

    ASP.NET代码调用SQL Server带DateTime类型参数的存储过程,如果DateTime类型参数的值是'0001/1/1 0:00:00'时,就会抛出异常“Message: SqlDate ...

  3. 对list遍历删除符合的数据

      例子

  4. 【慕课网实战】九、以慕课网日志分析为例 进入大数据 Spark SQL 的世界

    即席查询普通查询 Load Data1) RDD DataFrame/Dataset2) Local Cloud(HDFS/S3) 将数据加载成RDDval masterLog = sc.textFi ...

  5. vue学习-自动行合并的table

    测试的效果 测试的html源码截图 v-table在tableGroup.js中定义,以下就render方法,行的所有单元格都在tableGrouper.js中处理 render:function(h ...

  6. svn提交出现错误 svn: Working copy 'D:\...'locked.

    更新svn内容时出现如下的错误: svn: Working copy 'D:\tools\Workspaces\EclipseForNewSTLJ\javashop\b2c\src\main\weba ...

  7. hive on spark 参数设置

    ; ; set spark.executor.memory=5G;

  8. Jenkins关闭和重启实现方式.

    1.关闭Jenkins 只需要在访问jenkins服务器的网址url地址后加上exit.例如我jenkins的地址http://localhost:8080/,那么我只需要在浏览器地址栏上敲下http ...

  9. Java 线程池(ThreadPoolExecutor)原理解析

    在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...

  10. 腾迅云获取免费SSL证书并布置

    上次申请了SSL证书一直没时间布置,今天重新再来操作一次 首先需要申请SSL证书,腾迅云买的域名有免费一年的SSL证书申请,网址:https://console.cloud.tencent.com/s ...