前言前端
在阅读 《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
优势架构
缺点函数
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
优势优化
缺点this
实现二
/** * 实现二 */ 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
优势
缺点
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
优势
缺点
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
优势
缺点
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 的实例,而后再接着获取值。
这也意味着每次属性访问都须要作这样一个判断,而引擎已经围绕属性访问作了高度优化,懒得改,并且还下降速度。
不过除了这个工做以外,还会有一些其余的内容须要考虑,好比说:
关于使用 # 而不使用 private 下次再说吧 固然这些问题均可以被解决啦,就是麻烦了点。
而若是你选择 #,实现的方式将跟 JavaScript 对象属性彻底没有关系,将会使用 private slots 的方式以及使用一个新的 slot 查找语法,总之就是会比 private 的实现方式简单不少。
最后
为了帮助你们让学习变得轻松、高效,给你们免费分享一大批资料,帮助你们在成为全栈工程师,乃至架构师的路上披荆斩棘。在这里给你们推荐一个前端全栈学习交流圈:866109386.欢迎你们进群交流讨论,学习交流,共同进步。
当真正开始学习的时候不免不知道从哪入手,致使效率低下影响继续学习的信心。
但最重要的是不知道哪些技术须要重点掌握,学习时频繁踩坑,最终浪费大量时间,因此有有效资源仍是颇有必要的。
最后祝福全部遇到瓶疾且不知道怎么办的前端程序员们,祝福你们在日后的工做与面试中一切顺利。