媒介
在浏览 《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
长处
- 写法简朴
- 调试轻易
- 兼容性好
瑕玷
- 外部能够接见和修正
- 言语没有合营的机制,如 for in 语句会将一切属性罗列出来
- 定名争执
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
长处
- 无定名争执
- 外部没法接见和修正
瑕玷
- constructor 的逻辑变得庞杂。构造函数应当只做对象初始化的事变,如今为了完成私有变量,必需包括部份要领的完成,代码构造上略不清楚。
- 要领存在于实例,而非原型上,子类也没法运用 super 挪用
- 构建增添一点点开支
完成二
/**
* 完成二
*/
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 的实例,然后再接着猎取值。
这也意味着每次属性接见都须要做如许一个推断,而引擎已缭绕属性接见做了高度优化,懒得改,而且还下降速率。
不过除了这个事情以外,还会有一些其他的内容须要斟酌,比如说:
- 你必需将私有的 key 编码进每一个词法环境
- for in 能够遍历这些属性吗?
- 私有属性和一般属性同名的时刻,谁会屏障谁?
- 怎样防备私有属性的称号不被探测出来。
关于运用 # 而不运用 private 更多的议论能够参考这个 Issue。
固然这些题目都能够被处置惩罚啦,就是贫苦了点。
而假如你挑选 #,完成的体式格局将跟 JavaScript 对象属性完整没有关系,将会运用 private slots
的体式格局以及运用一个新的 slot 查找语法,总之就是会比 private 的完成体式格局简朴许多。
参考
ES6 系列
ES6 系列目次地点:https://github.com/mqyqingfeng/Blog
ES6 系列估计写二十篇摆布,旨在加深 ES6 部份知识点的明白,重点解说块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模仿完成、模块加载计划、异步处置惩罚等内容。
假如有毛病或许不严谨的处所,请务必赋予斧正,非常谢谢。假如喜好或许有所启示,迎接 star,对作者也是一种勉励。