it-swarm.asia

لماذا يمكنني الوصول إلى أعضاء TypeScript الخاصين عندما لا أكون قادرًا على ذلك؟

أنا أبحث عن تنفيذ أعضاء خاصين في TypeScript ، وأجده مربكًا بعض الشيء. لا يسمح Intellisense بالوصول إلى عضو خاص ، ولكن في JavaScript ، كل شيء هناك. هذا يجعلني أعتقد أن TS لا يقوم بتطبيق الأعضاء الخاصين بشكل صحيح. أي أفكار؟

class Test{
  private member: any = "private member";
}
alert(new Test().member);
93
Sean Feldman

كما هو الحال مع التحقق من النوع ، يتم فرض خصوصية الأعضاء فقط داخل برنامج التحويل البرمجي.

يتم تنفيذ خاصية خاصة كخاصية عادية ، ولا يُسمح بالوصول إلى رمز خارج الفصل.

لجعل شيئًا ما حقيقيًا داخل الفصل ، لا يمكن أن يكون عضوًا في الفصل ، سيكون متغيرًا محليًا تم إنشاؤه داخل نطاق دالة داخل التعليمة البرمجية التي تنشئ الكائن. هذا يعني أنه لا يمكنك الوصول إليه مثل عضو في الفصل ، أي باستخدام الكلمة الأساسية this.

85
Guffa

جافا سكريبت يدعم المتغيرات الخاصة.

function MyClass() {
    var myPrivateVar = 3;

    this.doSomething = function() {
        return myPrivateVar++;        
    }
}

في TypeScript ، سيتم التعبير عن ذلك على النحو التالي:

class MyClass {

    doSomething: () => number;

    constructor() {
        var myPrivateVar = 3;

        this.doSomething = function () {
            return myPrivateVar++;
        }
    }
}

تصحيح

يجب استخدام هذا النهج فقطبشكل مقتصدحيث تكون هناك حاجة ماسة إليه. على سبيل المثال ، إذا كنت بحاجة إلى تخزين كلمة مرور مؤقتًا مؤقتًا.

هناك تكاليف أداء لاستخدام هذا النمط (غير ذي صلة بـ Javascript أو TypeScript) ويجب استخدامها فقط عند الضرورة القصوى.

36
Martin

بمجرد دعم WeakMap متاح على نطاق واسع ، هناك تقنية مثيرة للاهتمام مفصلة في المثال رقم 3 هنا .

يسمح بالبيانات الخاصة ويتجنب تكاليف أداء مثال Jason Evans عن طريق السماح للبيانات بالوصول إليها من خلال طرق النموذج الأولي بدلاً من طرق المثال فقط.

تسرد صفحة MDN WeakMap المرتبطة دعم المتصفح في Chrome 36 و Firefox 6.0 و IE 11 و Opera 23 و Safari 7.1.

let _counter = new WeakMap();
let _action = new WeakMap();
class Countdown {
  constructor(counter, action) {
    _counter.set(this, counter);
    _action.set(this, action);
  }
  decrement() {
    let counter = _counter.get(this);
    if (counter < 1) return;
    counter--;
    _counter.set(this, counter);
    if (counter === 0) {
      _action.get(this)();
    }
  }
}
12
Ryan Thomas

شكراً لشون فيلدمان على ارتباطه بالمناقشة الرسمية حول هذه المسألة - راجع إجابته للحصول على الرابط.

قرأت المناقشة التي ربطها و إليك ملخصًا للنقاط الرئيسية:

  • الاقتراح: الخصائص الخاصة في المنشئ
    • لا يمكن الوصول إلى {problems: من وظائف النموذج الأولي
  • الاقتراح: الطرق الخاصة في المنشئ
    • (المشاكل: كما هو الحال مع الخصائص ، بالإضافة إلى فقد ميزة الأداء المتمثلة في إنشاء وظيفة مرة واحدة لكل فئة في النموذج الأولي ؛ بدلاً من ذلك ، يمكنك إنشاء نسخة من الوظيفة لكل مثيل
  • (الاقتراح: إضافة ملف تعريف الوصول إلى خاصية الوصول التجريدي وفرض الرؤية
    • (المشاكل: الحمل الرئيسي للأداء ؛ تم تصميم TypeScript للتطبيقات الكبيرة
  • (الاقتراح: يلف TypeScript بالفعل تعريفات أسلوب المنشئ والنموذج الأولي في الإغلاق ؛ وضع الأساليب والممتلكات الخاصة هناك.
    • (مشاكل وضع الخصائص الخاصة في هذا الإغلاق: تصبح متغيرات ثابتة ؛ لا يوجد واحد لكل مثيل
    • (مشاكل وضع الطرق الخاصة في هذا الإغلاق: ليس لديهم إمكانية الوصول إلى this دون حل بديل.
  • (الاقتراح: دمج أسماء المتغيرات الخاصة تلقائيًا
    • (وسيطات مضادة: هذا عبارة عن اصطلاح تسمية ، وليس بناء لغة. تشوهها بنفسك
  • الاقتراح: علق الطرق الخاصة بـ @private بحيث يمكن للمصغرات التي تدرك أن التعليق التوضيحي يقلل بشكل فعال من أسماء الطرق
    • لا حجج مضادة كبيرة لهذا واحد

إجمالي الحجج المضادة لإضافة دعم الرؤية في التعليمات البرمجية المنبعثة:

  • المشكلة هي أن جافا سكريبت نفسها لا تحتوي على معدلات رؤية - هذه ليست مشكلة في TypeScript
  • يوجد بالفعل نمط ثابت في مجتمع JavaScript: بادئة الخصائص والأساليب الخاصة مع الشرطة السفلية ، والتي تقول "تابع على مسؤوليتك الخاصة"
  • عندما قال مصممو TypeScript أن الخصائص والأساليب الخاصة حقًا "غير ممكنة" ، فإنهم يقصدون "غير ممكن في ظل قيود التصميم لدينا" ، وتحديداً:
    • و JS المنبعثة هو اصطلاحي
    • Boilerplate هو الحد الأدنى
    • لا توجد نفقات إضافية مقارنة مع JS OOP العادي
3
alexanderbird

في TypeScript ، لا يمكن الوصول إلى الوظائف إلا داخل الفصل. مثل

 enter image description here 

وسيظهر خطأ عند محاولة الوصول إلى عضو خاص. هنا هو المثال:

 enter image description here 

ملاحظة: سيكون على ما يرام مع جافا سكريبت ويمكن الوصول إلى كلتا الوظيفتين في الخارج.

2
Muhammad Awais

أدرك أن هذه مناقشة قديمة ، ولكن قد يكون من المفيد مشاركة حل بلدي لمشكلة المتغيرات والأساليب الخاصة المفترضة في TypeScript "تسرب" إلى الواجهة العامة لفئة JavaScript المترجمة.

بالنسبة لي ، هذه المشكلة تجميلية بحتة ، أي أنها تتعلق بالفوضى المرئية عند عرض متغير مثيل في DevTools. إصلاحي هو تجميع الإعلانات الخاصة معًا داخل فئة أخرى يتم بعد ذلك إنشاء مثيل لها في الفئة الرئيسية ويتم تعيينها لمتغير private (ولكن لا يزال مرئيًا بشكل عام في JS) باسم مثل __ (تسطير مزدوج أسفل السطر).

مثال:

class Privates {
    readonly DEFAULT_MULTIPLIER = 2;
    foo: number;
    bar: number;

    someMethod = (multiplier: number = this.DEFAULT_MULTIPLIER) => {
        return multiplier * (this.foo + this.bar);
    }

    private _class: MyClass;

    constructor(_class: MyClass) {
        this._class = _class;
    }
}

export class MyClass {
    private __: Privates = new Privates(this);

    constructor(foo: number, bar: number, baz: number) {
        // assign private property values...
        this.__.foo = foo;
        this.__.bar = bar;

        // assign public property values...
        this.baz = baz;
    }

    baz: number;

    print = () => {
        console.log(`foo=${this.__.foo}, bar=${this.__.bar}`);
        console.log(`someMethod returns ${this.__.someMethod()}`);
    }
}

let myClass = new MyClass(1, 2, 3);

عندما يتم عرض مثيل myClass في DevTools ، فبدلاً من رؤية جميع أعضائه "الخاصين" المختلطين مع الأعضاء العموميين حقًا (والتي يمكن أن تتسبب في فوضى بصرية في رمز الحياة الواقعية المعاد تشكيلها بشكل صحيح) ، ستراهم مجمعين بدقة داخل خاصية __ المنهارة:

 enter image description here 

1
Caspian Canuck