proposal-class-fields与proposal-private-methods定义了 Class 的私有属性以及私有方法,这 2 个提案已经处于 Stage 3,这就意味着它们已经基本确定下来了,等待被加入到新的 ECMAScript 版本中。事实上,最新的 Chrome 已经支持了 Class 私有属性。
那么,对于 Class 的私有属性与私有方法,它们究竟是什么呢?它们是怎样工作的?为什么要使用**#**符号来定义呢?
Class 的私有属性语法如下:
class Point {
#x;
#y;
constructor(x, y) {
this.#x = x;
this.#y = y;
}
equals(point) {
return this.#x === point.#x && this.#y === point.#y;
}
}
我们可以将其语法理解为 2 个部分:
私有属性与公共属性的定义方式几乎是一样的,只是需要在属性名称前面添加**#**符号:
class Foo {
publicFieldName = 1;
#privateFieldName = 2;
}
定义私有属性的时候也可以不用赋值:
class Foo {
#privateFieldName;
}
引用私有属性也只需要使用**#**就好了。
class Foo {
publicFieldName = 1;
#privateFieldName = 2;
add() {
return this.publicFieldName + this.#privateFieldName;
}
}
其中,**this.#**可以简化,去掉 this 也没问题,下面两种写法是等价的:
method() {
#privateFieldName;
}
method() {
this.#privateFieldName;
}
对于私有属性,我们是不可以直接通过 Class 实例来引用的,这也是私有属性的本来含义。但是有一种情况除外,在 Class 定义中,我们可以引用 Class 实例的私有属性:
class Foo {
#privateValue = 42;
static getPrivateValue(foo) {
return foo.#privateValue;
}
}
Foo.getPrivateValue(new Foo()); // >> 42
其中,foo是Foo的实例,在 Class 定义中,我们可以通过 foo 来引用私有属性**#privateValue**。
Class 的私有属性是提案proposal-class-fields的一部分,这个提案只关注 Class 的属性,它并没有对 Class 的方法进行任何修改。而 Class 的私有方法是提案proposal-class-fields的一部分。
Class 的私有方法语法如下:
class Foo {
constructor() {
this.#method();
}
#method() {
// ...
}
}
我们也可以将函数赋值给私有属性:
class Foo {
constructor() {
this.#method();
}
#method = () => {
// ...
};
}
我们不能直接通过 Class 实例引用私有属性,我们只能在 Class 定义中引用它们:
class Foo {
#bar;
method() {
this.#bar; // Works
}
}
let foo = new Foo();
foo.#bar; // Invalid!
另外,要做到真正的私有的话,我们应该无法检测这个私有属性是否存在,因此,我们需要允许定义同名的公共属性:
class Foo {
bar = 1; // public bar
#bar = 2; // private bar
}
如果我们不允许公共属性与私有属性同名,我们则可以通过给同名的公共属性复制监测该私有属性是否存在:
foo.bar = 1; // Error: `bar` is private! (报错,说明私有属性存在)
不报错也行:
foo.bar = 1;
foo.bar; // `undefined` (赋值失败,说明私有属性存在)
对于 subclass 应该同样如此,它也允许公共属性与私有属性同名:
class Foo {
#fieldName = 1;
}
class Bar extends Foo {
fieldName = 2; // Works!
}
关于 Class 私有属性的封装,可以参考Why is encapsulation a goal of this proposal?。
很多人都有一个疑问,为什么 JS 不能学习其他语言,使用private来定义私有属性和私有方法?为什么要使用奇怪的**#**符号?
使用 private 的话,代码要舒服很多:
class Foo {
private value;
equals(foo) {
return this.value === foo.value;
}
}
很多语言使用 private 来定义私用属性,如下:
class EnterpriseFoo {
public bar;
private baz;
method() {
this.bar;
this.baz;
}
}
对于这些语言属性,私用属性和公共属性的引用方式是相同的,因此他们可以使用 private 来定义私有属性。
但是,对于 JavaScript 来说,我们不能使用 this.field 来引用私有属性(我接下来会解释原因),我们需要在语法层面上区分私有属性和公共属性。在定义和引用私有属性的时候,使用**#**符号,私有属性与公共属性可以很好地区分开来。
引用私有属性的时候,我们需要this.#field,而不是this.field,原因如下:
class Dict extends null {
#data = something_secret;
add(key, value) {
this[key] = value;
}
get(key) {
return this[key];
}
}
new Dict().get("#data"); // 返回私有属性
因此,私有属性与公共属性的引用方式必须不一样,否则会破坏**this['field']**语法。
这篇文章遵循Creative Commons Attribution 4.0 International License。
原文:JavaScript's new #private class fields
译者:Fundebug
JS语言传统创建对象的方法一般是通过构造函数,来定义生成的,下面是一个使用function生成的例子。ES5是先新建子类的实例对象this,再将父类的属性添加到子类上,由于父类的内部属性无法获取,导致无法继承原生的构造函数
ES6 提供了更接近传统语言的写法,引入了 class(类)这个概念,作为对象的模板。通过class关键字,可以定义类
mixin一般翻译为“混入”、“混合”, 早期一般解释为:把一个对象的方法和属性拷贝到另一个对象上;Mixin是一种思想,用来实现代码高度可复用性,又可以用来解决多继承的问题,是一种非常灵活的设计模式
JS基于原型的类,一直被转行前端的码僚们大呼惊奇,但接近传统模式使用class关键字定义的出现,ES6的class只是个语法糖,其定义生成的对象依然构造函数。不过为了与构造函数模式区分开,我们称其为类模式。
class 是 ES6 的新特性,可以用来定义一个类,实际上,class 只是一种语法糖,它是构造函数的另一种写法。用法和使用构造函数一样,通过 new 来生成对象实例
ES6中的 class定义一个类, 其内部包含 constructor构造函数, 除了在构造函数显示的定义一些属性, 其余的默认都添加到这个类的原型对象上。以上代码 classProxy(prosen2) 返回的是包含一层拦截器的实例对象, 当读取 sayName这个函数的是和会出发 get拦截等操作。
使用jQuery可以给元素很方便的添加class和删除class等操作,现在原生的JavaScript也可以实现这个方法了。使用classList可以方便的添加class、删除class、查询class等。elementClasses 是一个 DOMTokenList 表示 element 的类属性 。
ES6中新增了class这个语法糖。此class并非java中的class,ES6中的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。其中有static关键字。
vue 指令以 v- 前缀标示,数据绑定的指令 v-bind:属性名, 简写为 :属性名, 简单的数据绑定例子如下;vue 的分隔符默认是 {{ }}, 在分隔符里面的字符串会被认为是数据变量,可以通过 方式设置class
class (类)作为对象的模板被引入,可以通过 class 关键字定义类。类简要说明,类的本质是function,是基本原型继承的语法糖。所以,JS中继承的模型是不会被改变的。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!