tc39 proposal: Class field declarations

提案地址:github.com/tc39/proposal-class-fields

该提案为 ES6 class 引入了类成员声明(Class field declarations)语法,包括公开成员和私有成员。目前处于 Stage 3 阶段。

下面举一个例子:

// 例子 1 
class Foo {
    publicVar = 1
    #privateVar = 2

    getPrivateVar() {
        return this.#privateVar
    }
}

const foo = new Foo()

foo.publicVar
foo.getPrivateVar()

公开成员在 class 中,直接以类似赋值语句的形式声明;私有成员的声明需要带上 #,访问的时候也要带上它。

可以把上面的代码简单理解成下面这种书写方式:

// 例子 2
class Foo {    
    constructor() {
        this.publicVar = 1
        this._privateVar = 2
    }

    getPrivateVar() {
        return this._privateVar
    }
}

const foo = new Foo()

foo.publicVar
foo.getPrivateVar()

这种写法近似正确语义,但不精确。比如:

  • public fields(也就是这里的 publicVar)底层其实是使用 Object.defineProperty 的方式([[Define]] 语义)定义的,而不是 this.field = value 的方式([[Set]] 语义)定义的。
  • private fields 要能真正对外隐藏成员变量,而上面的实现通过 foo._privateVar 依旧能拿到。

当然,我们还可以更近一步,使用 babel 转码“例子 1 ”的代码

"use strict";

function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }
  return obj;
}

function _classPrivateFieldGet(receiver, privateMap) {
  var descriptor = privateMap.get(receiver);
  if (!descriptor) {
    throw new TypeError("attempted to get private field on non-instance");
  }
  if (descriptor.get) {
    return descriptor.get.call(receiver);
  }
  return descriptor.value;
}

var _privateVar = new WeakMap();

class Foo {
  constructor() {
    _defineProperty(this, "publicVar", 0);

    _privateVar.set(this, {
      writable: true,
      value: 0
    });
  }

  getPrivateVar() {
    return _classPrivateFieldGet(this, _privateVar);
  }
}

const foo = new Foo();
foo.publicVar;
foo.getPrivateVar();

babel 的转码更精确一些,定义公共成员使用了 _defineProperty 方法,而私有成员则使用 WeakMap 变量贮藏。

不过要再深究一点的话:

  • 对于定义公共成员的 _defineProperty 方法,它并不是完全使用的 [[Define]] 语义,与提案中描述的不一致。
// √ 下列代码经 babel 转义后,语义不变
class A {
  set x(value) { console.log(value); }
}
class B extends A {
  x = 1;
}

// × 下列代码经 babel 转义后,采用 [[Set]] 语义,与提案中描述不符
class B {
  x = 1;
}
  • 而私有成员的 WeakMap 实现,依旧是通过 _privateVar 的形式实现,不过值通过 WeakMap 被间接包装了一下。

(完)

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!