美文网首页
JS - 面向对象 - 私有属性

JS - 面向对象 - 私有属性

作者: Iceesong | 来源:发表于2018-08-04 16:10 被阅读0次

    面向对象

    在日常业务中,我们总是需要使用 对象 将一个事物抽象出来,而考虑安全等因素,又需要对其中部分属性进行隐藏显示,在面对对象的 java、 C 等编程语言,有语法规范设定,而在 JavaScript 中没有, 目前只能通过变通方法模拟实现。

    举栗子

    在 《Eloquent_JavaScript》 习题中,题目要求通过解锁获取到 _content,同时说明了不予许直接访问 _content ,如下:

        let box = {
            locked: true ,      // 放这不大安全哦
            unlock: function () {
                this.locked = false; 
            }, 
            lock: function () {
                this.locked = true; 
            }, 
            _content: [],       // 放这不大安全哦
            get content () {
                if (this.locked) throw new Error(" Locked !");
                return this._content;
            } 
        }
    

    相比解题,可能大部分人也会顺带想想,得让 _content 私有化,只能由内部指定的方法访问才行,不然像这样就很尴尬了

        // 直接重新指向,破坏内部数据
        box._content = null
    
        // 再正常访问 ,啥都没了
        box.unlock()
        box.content     // =>  null 
    
        // 或者
        box.locked = false
        box.content     // =>  null 
    

    闭包

    还是闭包,毕竟就为储存变量而生的嘛,引申下就是对外(函数)变量 私有 ,对内 公开

        let box = (function(){
          let locked = true     
          let _content = []      // 私有属性作为 闭包变量 存储,只能由内部函数获取
          return {
            unlock: function () {
              locked = false; 
            }, 
            lock: function () {
              locked = true; 
            }, 
            get content () {     // 唯一对外开放的可以访问到 content 属性的方法
              if (locked) throw new Error(" Locked !");
              return _content;
            } 
          }
        })()
    

    再来试试

        box._content = null
    
        //一切正常,因为上面已经无法指向 _content 了
        box.unlock()    
        box.content     // =>  [] 
    
        // 同理
        box.locked = false
        box.content     // =>  [] 
    

    上面的是对象实例,要用扩展到类来实现 私有属性 呢
    常见的构造函数

      // 常用显式展示 
        function Person(name, age) {
            this.name = name
            this.age = age
        }
    
        name = 'ice'
        age = 18
        p1 = new Person(name,age)         // => {name: "ice", age: 18}
    

    当我需要这属性不再显示的表现,只能 固定接口 访问时

      // 常用隐式展示 
        function Person(name, age) {
            this.name = name
            this.getAge = function() {
                return age - 5
            }
        }
        p2 = new Person(name,age)         // => {name: "ice", getAge: ƒ}
    

    功能上可行,但在性能有个缺点,因为我们是直接在 构造函数 Person 内再创建一个函数(闭包),以此隐藏属性,而每一次构建实例也都对多创建这一个函数,所以一定程度上内存消耗产生影响。

    WeakMap 销毁

    MDN 上 关于 WeakMap 有句这样的描述:

    每个键对自己所引用对象的引用是 "弱引用" ,这意味着,如果没有其他引用和该键引用同一个对象,这个对象将会被当作垃圾回收。

    对此,结合下上面的解决办法,缓解内存问题

      // 目前最优解 (占内存更小,一旦访问指针丢失,则会自动销毁)
      let Person = function(){
      let wm = new WeakMap()
    
      return class Person {
        constructor(name,age) {
          this.name = name
          wm.set(this, {
            age: age
          })
        }
    
        get age() {
          return wm.get(this).age
        }
    
      }
    }()
    

    相关文章

      网友评论

          本文标题:JS - 面向对象 - 私有属性

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