JavaScript实现私有成员

JavaScript从某些角度来看是一门残缺的语言,即使es6在语法层面上实现了类和继承,但也只不过是语法糖而已,而且还没有实现私有成员。

当然,JavaScript没有什么不能靠hack来实现的,下面介(摘)绍(抄)一下几种模拟出私有成员的方法。

基于约定

如果使用ES6,约定以下划线_开头的成员名作为私有成员。

class Animal {
  constructor() {
    this._notPublicProperty = 2
  }
  _notPublicMethod () {
    return this._notPublicProperty
  }
}

这样貌似也勉强够用,但是只能靠使用者的自觉,遵守命名规则。

ES5基于闭包

function  Animal() {
}

Animal.prototype = (function () {
  var self = this;
  var _notPublicProperty = 2;
  function _notPublicMethod() {
    return _notPublicProperty;
  }

  return {
    constructor: Animal,
    getNotPublicProperty: function() {
      return _notPublicMethod.call(this)
    }
  }
}())

var dog = new Animal()
console.log(dog.getNotPublicProperty());  // 2
console.log(dog._notPublicMethod());  // ReferenceError: _notPublicProperty is not defined

Symbol

复习一下JavaScript的六种基本数据类型

undefined null number string object boolean

ES6为JavaScript引入了一种新的基本数据类型 — Symbol
Symbol是一个全局函数,每调用一次就会产生一个唯一的字符串,关于Symbol的详细介绍可以参见 阮一峰的ES6教程

const _notPublicMethod = Symbol()
const _notPublicProperty = Symbol()
class Animal {
  constructor() {
    this[_notPublicProperty] = 2;
  }
  [_notPublicMethod]() {
    return this[_notPublicProperty]; // 必须用中括号
  }
  getNotPublicProperty() {
    return this[_notPublicMethod]()
  }
}

var dog = new Animal()

console.log(dog.getNotPublicProperty());  // 2
console.log(dog._notPublicMethod());  // ReferenceError: _notPublicProperty is not defined

每次都要创建一个Symbol还是不那么完美,但是已经不错了。

WeakMap

Map和WeakMap都是ES6新引入的数据结构。
Map和Object类似,都是hash结构。Object的键只能是字符串,而Map打破了这一限制,键可以是任意数据类型,而WeakMap比Map要弱一点,键只能是对象;且WeakMap的键名所指向的对象,不计入垃圾回收机制。

主要的思路是,在类的级别上创建一个 WeakMap 容器,用于存储各个实例的私有成员


const store = new WeakMap()

class Animal {
  constructor() {
    var self = this;

    function _notPublicMethod() {
      return store.get(this)._notPublicProperty
    }

    store.set(this,{
      _notPublicProperty: 2,
      _notPublicMethod: _notPublicMethod.bind(self)
    })
  }

  getNotPublicProperty() {
    return store.get(this)._notPublicMethod
  }
}

var dog = new Animal()

console.log(dog.getNotPublicProperty());  // 2
console.log(dog._notPublicMethod());  // ReferenceError: _notPublicProperty is not defined

貌似引入WeakMap使得问题更加复杂,还是我的打开方式不对?

最后,还是希望babel和node能够尽快支持最新的提案,使用#来自然的标识私有成员,写hack真的很hack啊!

参考

    原文作者:Quilljou
    原文地址: https://www.jianshu.com/p/806eacda4c0e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞