No prefix! operator is Ok!

栏目: JavaScript · 发布时间: 5年前

内容简介:所有在我对原有提案的修改中,核心不是“不用原有提案:修改的提议:

所有在我对原有提案的修改中,核心不是“不用 # 字符”,而是将它从一个前缀字符,变成了一个操作符。这一方面是使“声明语法”与“表达式运算”分开,另一方面也让这些修改与ECMAScript规范保持在语法上的一致性。

原有提案: https://github.com/tc39/proposal-class-fields

修改的提议: #issuecomment-429533532

1. 为什么是":“而不是”="?

在所有类、对象等声明性质的语法中,":"是表明"key/value pair"的,既然这里的私有字段仍然是“key/value pair”,那么仍然建议使用该符号。而原提案建议使用 = 并且与TypeScript保持一致,却忽略了TypeScript中完整的语法 x: number = 100 中, : 是指示类型的,而不是用于指示值。——这与ECMAScript的一般规则并不一致。

ECMAScript规范事实上是沿用了“旧式的对象字面量”的属性声明与初值的语法,亦即是:

obj = {
    x: 100,
    y: 100
}

注意在这个语法中”有或没有 , 号都是接受的,但如果有 , 号则称为一个List,且整个声明是以一个“没有 , 号的单个属性声明”结束的。——这与传统的对象字面量声明语法一致。

在ECMAScript中,类声明一定程度上沿用和扩展了这一语法。一方面,把“方法声明”给到了对象字面量声明;另一方面,从对象字面量那里把“get/setter声明”拿了过来。而与TypeScript类似的 = xxxx 语法,尽管也是一个称为 Initializer 的语法组件,也的确出现在了对象初始化语法中,但是作为错误语法来识别的(CoverInitializedName):

PropertyDefinition: CoverInitializedName
     Always throw a Syntax Error if code matches this production.

所以,回到最前面的说明,推荐的语法设计是:

// Because
obj = {
    data: 100,
    foo() {
        ....
    }
}

// YES
class f {
    data: 100,
    foo() {
        ...
    }
}

// NO!!!
class f {
    data = 100;
    ...
}

这样使用 f() 类构造出来的对象实例,与用相似语法声明的对象字面量是类似的。不存在语法设计上的“例外(unexpected)”。

2. 为什么是"private x"而不是"#"?

在现有类、对象等声明语法中是使用限定词来指示成员性质的,例如 staticget 等。除了生成器函数之外,并不使用限定符号或“前缀(prefix)”,因此我建议用限定词 private 来扩展类声明语法,而反对原提案中使用 # 作为限定符来声明类私有字段(private field of class)。例如:

// YES
class f {
    private data: 100  
}

// NO!
class f {
    #data = 100;
}

3.为什么是",“而不是”;"?

在所有的列表(List)中,ECMAScript采用的分隔符都是 , 号,例如参数列表、对象/数组成员列表,以及导入导出的名字列表,还有变量 var 声明的名字列表等等。而 ; 在语法中惯例是用作语句结束符或分隔符,包括你所见的各种(任意的)语句,以及 for(;;) 中的子句等等。我们既然是在声明类或对象的“成员列表”,那么显然应该是按“列表(List)”的规则处理成 , 为好,怎么会用到 ; 号了呢?

TypeScript中在这个位置是这样声明的:

class f {
    data: string = 'in typescript';
    ...
}

留意这里的语法特点:符号 : 是用于指示类型的,因此初值声明使用了 = 。这个声明与 var 语句声明类似,TypeScript将这里处理成了 ; 是可以理解的。但ECMAScript何必要绕开现成的 , 号不用,去使用在这里毫无意义的 ; 号呢?

4.最后一个","号的问题

ECMAScript既然已经接受了对象字面量声明的末尾逗号(object literal trailing commas),那么下面两种声明都可以是合法的了:

// 推荐
class f {
    data: 100,
    foo() {
        ...
    }
}

// (可接受)
class f {
    ...,  // more, a list with ','
    data: 100
    foo() {
        ...
    }
}

5.其它的声明示例

包括:

var data = 'outer';

class f {
  // reference
  data,  // outer reference, no computed

  // public
  data: 100,  // for object, equ: f.prototype.data = 100
  static data: 100, // for class, equ: f.data = 100
  ["da"+"ta"]: 100, // computed
  static ["da"+"ta"]: 100, // computed

  // private
  private data: 100,  // normal private object properties
  private ["da"+"ta"]: 100,  // computed private object properties, and symbol keys
  private static data: 100, // for class static field
  private static ["da" + "ta"]: 100, // computed

  // get&setter, etc
  private get data() { ... }
  ...
}

6.私有属性的存取

私有属性的存取是一个大问题,也是 # 语法争议的焦点。首先必须确定的是:私有属性存取的语义是什么?

在原提案中,私有属性存取是将 # 作为一个前缀(prefix),而存取运算仍然是 .[] 运算符。因此,本质上来说,存取运算的操作没变,但是需要在存取中判断属性名的前缀是否是 # 字符。如下例:

// 原提案
class f {
    #data = 100;
    foo() {
        console.log(this.#data);  // "#"是前缀,而"."是存取运算符
    }
}

根本原因出在 . 运算检测 data 是否是私有成员的成本过高。例如:

// 示例:一个不太可行的方案
class f{
    data = 100; // 假设这里是私有成员
    foo() {
        console.log(this.data);  // 假设这里的this.data指向私有成员
    }
}
x = new f;
x.data = '200';
f(); // 应该显示200还是100?

那么在上面这个例子中, x.data 添加了一个公开的属性时,foo()方法是无法识别用户代码的意图的。

所以在旧的提案中需要使用 # 前缀。但是,仔细思考这个问题:

  • 私有字段列表与自有成员列表必须是同一个吗?

当然不需要。那么为什么不为私有字段列表安排一个专门的运算符呢?只要“像使用super一样”限定它使用的上下文就好。因此,新的语法设计如下:

class f{
    data: 100,
    foo() {
        console.log(this#data);
    }
}

也就是说 # 现在是当作一个运算符(operator )在用,而不是一个前缀(prefix)。

但为什么是 #

答案是:老实说,我也想不到更好的了。如果你能找一个大家都满意的,我接受。

NOTE:

一个备选的运算符可以是 -> ,但老实说我认为比 # 更差劲。

7.其它

  • 在本方案中,是默认用“对象或类”的自有成员列表来实现的,这意味着总是需要用类似 this#xxx 的语法来存取它。不过这并非唯一的方案。

  • 关于类似于”采用词法上下文“来实现私有成员的问题,我另写文章来讨论吧。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ACM程序设计培训教程

ACM程序设计培训教程

吴昊 / 中国铁道 / 2007-8 / 28.0

《ACM程序设计培训教程》不是这些专门问题的教科书,所以对这些问题所涉及知识的介绍不多,主要是分析一个个案例,介绍专属于ACM程序设计的方法和技巧。一起来看看 《ACM程序设计培训教程》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换