JavaScript实现私有成员

作者: Quilljou | 来源:发表于2017-07-07 22:18 被阅读105次

    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啊!

    参考

    相关文章

      网友评论

        本文标题:JavaScript实现私有成员

        本文链接:https://www.haomeiwen.com/subject/gowrhxtx.html