仅在具有 class 实例的 class 中访问 class 的私有成员

Access to private member of a class only inside a class that has an instance of that class

我正在实现一个链表。 我有两个 classes NodeSingleLinkedList。现在我需要从 SingleLinkedList class 访问 Node class 的私有成员,但在外部我认为这是不可能的;通过这种方式,我可以 return 来自 SingleLinkedListNode 实例,并且用户无法使用该节点访问所有数据结构。在 Java 中,当一个 class 具有另一个 class 的对象(组合)时可以这样做,在 C++ 中有朋友 classes。我如何在 Java 脚本中执行此操作?

以下是我正在实施的 "example toy" 以测试我目前所掌握的知识并查看会出现什么问题

  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);

例如,如果我将 class Node
next属性 设为私有 我无法再访问 SingleLinkedClass 中的变量。相反,如果我保留这样的代码,并且我 return 来自某个函数的 Node 实例,用户可以使用下一个 属性 访问我几乎所有的结构。 Java脚本中是否存在一些可能简单的解决方案? 我想尽可能清楚。因此我想做的是:

  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() return 一个节点,你可以用它扫描整个列表。不好。因此我想做:

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

使用最后一个版本,当我 return 来自 get() 的节点不再是问题,因为 class Node 的成员即 #next 是私有的,但以这种方式我有一个错误,因为即使在 SingleLinkedClass 中,成员 #next 也是不可见的。

我希望这能澄清我的问题

私有标识符是词法范围的,所以 #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 的私有字段中获取信息。举个例子,看评论:

"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 的实际使用是在它存在的范围内。

另一种选择是使NodeSingleLinkedList: