【问题标题】:Access to private member of a class only inside a class that has an instance of that class仅在具有该类实例的类内部访问该类的私有成员
【发布时间】:2020-04-28 13:52:18
【问题描述】:

我正在实现一个链接列表。 我有两个班级NodeSingleLinkedList。现在我需要从SingleLinkedList 类访问Node 类的私有成员,但在外面我认为这是不可能的;通过这种方式,我可以从SingleLinkedList 返回一个Node 实例,并且用户无法使用该节点加入所有数据结构。在 Java 中,当一个类具有另一个类的对象(组合)时可以做到这一点,而在 C++ 中则有友元类。我怎样才能在 Javascript 中做到这一点?

以下是我正在实施的“示例玩具”,以测试我目前获得的知识并看看会出现什么问题

  class Node {
             next = null;
             constructor(value) {
                this.value = value;

             }
          }

          class SingleLinkedList {
             #size = 0;
             #head = null;
             #tail = null;

             // read only get accessor property
             get size() {
                return this.#size;
             }

             isEmpty() {
                return this.#size === 0;
             }

            // insert a new Node (in tail) with the desired value
         push(value) {
            const node = new Node(value);

            if (this.isEmpty()) {
               this.#head = node;
            } else {
               this.#tail.next = node;
            }

            // the following instructions are common to both the cases.
            this.#tail = node;
            this.#size++;

            // to allow multiple push call
            return this;
         }



        get(index){
        if(index<0 || index>=this.#size)
           return null;

        let current = this.#head;


        return current.value;
     }


          }

          const myLinkedList = new SingleLinkedList();
          myLinkedList.push(3).push(5);

例如,如果我将 Node 类的 nextproperty 设为私有@
我无法再访问我的SingleLinkedClass 中的变量。相反,如果我留下这样的代码并从某个函数返回一个Node 实例,那么用户可以使用下一个属性加入几乎所有我的结构。它是否存在一些可能很简单的 Javascript 解决方案? 我想尽可能清楚。因此,我想要做的是:

  class Node {
         next = null;
         constructor(value) {
            this.value = value;

         }
      }

      class SingleLinkedList {
         #size = 0;
         #head = null;
         #tail = null;

         // read only get accessor property
         get size() {
            return this.#size;
         }

         isEmpty() {
            return this.#size === 0;
         }


        // insert a new Node (in tail) with the desired value
     push(value) {
        const node = new Node(value);

        if (this.isEmpty()) {
           this.#head = node;
        } else {
           this.#tail.next = node;
        }

        // the following instructions are common to both the cases.
        this.#tail = node;
        this.#size++;

        // to allow multiple push call
        return this;
     }


        get(index){
        if(index<0 || index>=this.#size)
           return null;

        let current = this.#head;


        return current; //NOW RETURN A NODE
     }

      const myLinkedList = new SingleLinkedList();
      myLinkedList.push(3).push(5);

      const myNode = myLinkedList.get(0); //RETURN NODE

现在,在上面的代码中,get() 返回一个节点,您可以使用它扫描整个列表。不好。因此我想做:

class Node {
         #next = null; //PRIVATE MEMBER
         constructor(value) {
            this.value = value;

         }
      }

      class SingleLinkedList {
         #size = 0;
         #head = null;
         #tail = null;

         // read only get accessor property
         get size() {
            return this.#size;
         }

         isEmpty() {
            return this.#size === 0;
         }


        // insert a new Node (in tail) with the desired value
     push(value) {
        const node = new Node(value);

        if (this.isEmpty()) {
           this.#head = node;
        } else {
           this.#tail.#next = node; //ERROR
        }

        // the following instructions are common to both the cases.
        this.#tail = node;
        this.#size++;

        // to allow multiple push call
        return this;
     }



        get(index){
        if(index<0 || index>=this.#size)
           return null;

        let current = this.#head;


        return current; //NOW RETURN A NODE
     }



      }

      const myLinkedList = new SingleLinkedList();
      myLinkedList.push(3).push(5);
      console.log(myLinkedList.toString());
      const myNode = myLinkedList.get(0); //RETURN NODE,NO MORE A PROBLEM

在最后一个版本中,当我从 get() 返回一个节点时不再是问题,因为 Node 类的成员,即 #next 是私有的,但这样我有一个错误,因为即使在 @ 987654338@ 成员#next 不可见。

我希望这能澄清我的问题

【问题讨论】:

  • 为什么要将Node(链接列表的内部)返回给用户?
  • 您能否缩短这些代码示例,以便更早地指出要点并更容易发现您的 sn-ps 之间的差异?
  • @Bergi 从一些函数返回一个节点大大简化了我必须实现的其他函数的实现(可以重用返回节点的函数)。此外,我缩短了一点代码
  • 这是关于将节点返回给您自己,而不是返回给用户。您也可以(应该)将这些可重用的辅助方法设为私有。
  • @Bergi 否,因为这些方法既是用户方法又是内部方法。但我希望当他们从我的类 LinkedList 调用时,我可以访问他们的私有成员(节点类,即返回的类型实例),而不是从外部调用它们(用户调用)没有。

标签: javascript oop design-patterns es6-class


【解决方案1】:

私有标识符是词法范围的,因此#size 等在SingleLinkedList 之外是不可访问的。但是有几种方法可以做到这一点。

最简单的就是让NodeSingleLinkedList:

"use strict";
class SingleLinkedList {
    #size = 0;
    
    constructor(size) {
        this.#size = size;
    }

    static Node = class Node {
        example(list) {
            console.log(`The size of the list is ${list.#size}`);
        }
    }
}
const Node = SingleLinkedList.Node;

// The `Node` code has access to `SingleLinkedList`'s private field:
const l = new SingleLinkedList(42);
const n = new Node();
n.example(l); // "The size of the list is ${getSize(list)}"

由于作用域是词法的,并且Node 的所有代码都在SingleLinkedList 的作用域内,所以效果很好。

如果您不希望它们嵌套,您可以让SingleLinkedListNode 提供一个只有Node 可以访问的函数,这将使NodeSingleLinkedlist 的私人获取信息字段。这是一个示例,请参见 cmets:

"use strict";
const {Node, SingleLinkedList} = (() => {
    // A function SingleLinkedList will fill in
    let getSize;

    // Create the class
    class SingleLinkedList {
        #size = 0;
        
        constructor(size) {
            this.#size = size;
        }

        // This is a temporary function for filling in `getSize`
        static boot() {
            getSize = list => list.#size;
        }
    }

    // Fill in `getSize`
    SingleLinkedList.boot();
    delete SingleLinkedList.boot;

    // Find the `Node` class, which uses `getSize`
    class Node {
        example(list) {
            console.log(`The size of the list is ${getSize(list)}`);
        }
    }

    // Return them; `getSize` is entirely private to the code
    // in this function, nothing else can use it
    return {Node, SingleLinkedList}
})();

// The `Node` code has access to `SingleLinkedList`'s private field:
const l = new SingleLinkedList(42);
const n = new Node();
n.example(l); // "The size of the list is ${getSize(list)}"

之所以有效,是因为#size 的实际使用在它存在的范围内。

另一种选择是使Node SingleLinkedList:

【讨论】:

  • 对不起,也许我必须把我想要的东西写得更好。我将用一个例子来解释这个问题
  • @Umbert - 据我所知,上述问题与您更新后的问题之间的唯一区别是您希望在SingleLinkedList 中访问Node 的私人成员,而不是其他方式大约。这是完全相同的事情,您只需交换类(或者甚至为两个类做同样的事情,如果您希望它们都可以访问另一个私有的东西)。
  • @是的,这是真的。换班就够了。聪明的解决方案,即使代码有点脏
  • @and 使用这两种解决方案,我不能再将这两个类放在两个单独的模块中
  • 是的,要做到这一点,您必须更广泛地公开事情。隐私是有代价的。 :-)
猜你喜欢
  • 1970-01-01
  • 2019-05-12
  • 2013-09-20
  • 2016-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 2020-01-19
相关资源
最近更新 更多