เข้าถึงสมาชิกของคลาสภายนอกใน TypeScript

ตั้งแต่ TypeScript 1.6 เราสามารถสร้างคลาสภายในได้อย่างง่ายดายด้วย นิพจน์คลาส ในภาษาอื่นๆ ที่เน้น OOP เป็นหลัก เช่น Java คลาสภายในสามารถเข้าถึงสมาชิกของคลาสภายนอกได้ แม้แต่คนส่วนตัว

ลักษณะการทำงานนี้คล้ายกับแนวคิดของการปิด โดยที่ฟังก์ชันสามารถเข้าถึงตัวแปรจากขอบเขตที่ถูกกำหนดไว้

เหตุใดฉันจึงไม่สามารถทำได้ใน TypeScript ข้อมูลจำเพาะของคลาสใน ECMAScript 2015 มีบทบาทที่นี่หรือไม่

รหัสที่นำเสนอลักษณะการทำงานที่คาดหวัง:

class OuterClass {
    private outerField = 1337;

    public InnerClass = class { 
        public accessOuter() {
            return this.outerField; // outerField not defined
        }
    }
}

var outer = new OuterClass();
var inner = new outer.InnerClass();
var win = inner.accessOuter();

person Piotr Lewandowski    schedule 02.08.2016    source แหล่งที่มา
comment
ดู stackoverflow.com/a/45244695/279393 เพื่อดูวิธีอื่นในการบรรลุเป้าหมายนี้   -  person bnieland    schedule 21.07.2017


คำตอบ (4)


ง่ายกว่าที่จะเข้าใจว่าทำไมคุณไม่สามารถทำเช่นนั้นได้หากคุณดูจาวาสคริปต์ที่คอมไพล์แล้วของโค้ดของคุณ:

var OuterClass = (function () {
    function OuterClass() {
        this.outerField = 1337;
        this.InnerClass = (function () {
            function class_1() {
            }
            class_1.prototype.accessOuter = function () {
                return this.outerField; // outerField not defined
            };
            return class_1;
        }());
    }
    return OuterClass;
}());

อย่างที่คุณเห็น outerField ถูกกำหนดให้เป็นสมาชิกของ OuterClass ดังนี้:

this.outerField = 1337;

เมื่อคุณพยายามเข้าถึงมันใน InnerClass คุณทำ:

return this.outerField;

แต่ this ในที่นี้คืออินสแตนซ์ของ class_1 ไม่ใช่ OuterClass ดังนั้นจึงไม่มี outerField ใน this
นอกจากนี้ คุณไม่มีสิทธิ์เข้าถึงจากคลาสภายในไปยังอินสแตนซ์ของคลาสภายนอก

วิธีแก้ปัญหานี้ใน java เป็นเช่นนั้น:

class OuterClass {
    private int outerField = 1337;

    public class InnerClass {
        public int accessOuter() {
            return OuterClass.this.outerField;
        }
    }
}

แต่ไม่มีอะไรเทียบเท่ากับ OuterClass.this.outerField ใน typescript/javascript
ดูคลาสภายในของ typescript เหมือนคลาสภายในแบบคงที่ใน java แต่ที่นี่คุณจะสามารถเข้าถึงคุณสมบัติสาธารณะเท่านั้น:

class OuterClass {
    public static outerField = 1337; // has to be public

    public InnerClass = class { 
        public accessOuter() {
            return OuterClass.outerField;
        }
    }
}

คุณสามารถส่งอินสแตนซ์ของคลาสภายนอกไปยังคลาสภายในได้:

class OuterClass {
    public outerField = 1337;

    public InnerClass = class {
        constructor(private parent: OuterClass) {}

        public accessOuter() {
            return this.parent.outerField;
        }
    }
}

แต่ขอย้ำอีกครั้งว่า คุณจะต้องมี outerField สาธารณะ


แก้ไข

ในกรณีที่คุณต้องการบรรลุผลสำเร็จที่จะจำลองพฤติกรรมที่จำเป็น (นั่นคือ อินสแตนซ์คลาสภายในจะมีสิทธิ์เข้าถึงสมาชิกคลาสภายนอกส่วนตัว) คุณสามารถดำเนินการดังนี้:

interface OuterClassProxy {
    outerField: number;
}

interface IInnerClass {}

class OuterClass {
    private outerField = 1337;

    static InnerClass = class implements IInnerClass {
        constructor(private parent: OuterClassProxy) {}

        public accessOuter() {
            return this.parent.outerField;
        }
    }

    public createInnerClass(): IInnerClass {
        let outerClassInstance = this;

        return new OuterClass.InnerClass({
            get outerField(): number {
                return outerClassInstance.outerField;
            },
            set outerField(value: number) {
                outerClassInstance.outerField = value;
            }
        });
    }
}

งานค่อนข้างเยอะแต่ก็จะทำได้

person Nitzan Tomer    schedule 03.08.2016

คำตอบของ @ Nitzan นั้นยอดเยี่ยมมาก ฉันแค่อยากจะเสริมว่าเมื่อเร็ว ๆ นี้ฉันเพิ่งค้นพบสิ่งนี้ อาจช่วยได้:

class Outer {

    constructor() {
        this.val = 1337;
    }

    get Inner() {
        let Outer = this;
        return class {
            accessVal() { return Outer.val; }
        }
    }

}

new (new Outer()).Inner().accessVal(); // 1337
person Kosmas Papadatos    schedule 26.10.2016
comment
อาจเป็นความคิดที่ดีที่จะเพิ่มอินเทอร์เฟซสำหรับคลาสภายในที่ใช้งาน - person eddiewould; 09.07.2017

นี่คือวิธีที่ถูกต้องในการทำเช่นนี้ใน typescript:

class OuterClass {
  private outerField = 1337;

  get InnerClass() {
    const thatOuterField = this.outerField // <-- Notice this addition
    return   class {
      public accessOuter() {
        return thatOuterField; // outerField not defined
      }
    }
  }


}

let outer = new OuterClass();
let inner = new outer.InnerClass();
let win = inner.accessOuter();

alert(win); // test works!

ไม่จำเป็นต้องมีอะไรซับซ้อน

person Somo S.    schedule 15.04.2017
comment
นี่เป็นแนวทางเดียวกับที่ Kosmas โพสต์ไว้แล้วเมื่อ 6 เดือนก่อน - person phil294; 24.11.2017

อันนี้ไม่ได้ผลแย่สำหรับฉัน:

function use<T>(value: T) {return new class {with<U>(f: (value: T) => U) {return f(value)}}}

class OuterClass {
    private outerField = 1337;

    InnerClass = use(this).with(outerThis => class { 
        accessOuter() {
            return outerThis.outerField; // outerField not defined
        }
    }
}
const outer = new OuterClass()
const inner = new outer.InnerClass()
const win = inner.accessOuter()
console.log(win)
person Nirvana    schedule 16.04.2021