برنامه نویسی

خصوصی در مقابل #خصوصی – انجمن DEV

Summarize this content to 400 words in Persian Lang

مقدمه (با نام مستعار شما می توانید این قسمت را نادیده بگیرید)چند هفته پیش در محل کار حواس من پرت شد و به طور تصادفی این وبلاگ را به عنوان یک مطلب نوشتم src/readme.md. اکنون که می‌خواهم آن شاخه را در زمان خودش ادغام کنم تا آن readme را حذف کنم، اما دوست دارم فکر کنم که بیش از 4 نفر دیگر در تیم من ممکن است این دیدگاه جالب باشد. بنابراین اکنون آن را همانطور که هست به شما ارائه می کنم. کد نویسی مبارک!

سلام

تصمیم گرفتم قراردادی را که در این پروژه در مورد سبک TypeScript خصوصی و سبک خصوصی ECMAScript استفاده می‌کردم، یادداشت کنم.

class Foo {
private bar: string;

constructor() {
this.bar = ‘secret sauce’;
}
}

console.log(new Foo().bar); // TypeScript error

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در TypeScript می توانید از private کلمه کلیدی برای علامت گذاری فیلدها، ویژگی ها و متدها به عنوان “خصوصی” (فقط از داخل همان کلاس قابل دسترسی است).با این حال، هنگامی که این کد کامپایل شد، این محدودیت دیگر وجود ندارد زیرا private بخشی از جاوا اسکریپت نیست.

بسته به پیکربندی TypeScript شما، کامپایلر هر دو از سوء استفاده از فیلد خصوصی شکایت خواهد کرد. اما هنوز هم کامپایل و کد زیر را منتشر کنید.

class Foo {
constructor() {
this.bar = ‘secret sauce’;
}
}

console.log(new Foo().bar); // logs “secret sauce”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

گزینه جایگزین استفاده از اصلاح‌کننده خصوصی ECMAScript است که با پیشوند نام با هش انجام می‌شود. #.

class Foo {
#bar: string;

constructor() {
this.#bar = ‘secret sauce’;
}
}

console.log(new Foo().#bar); // TypeScript error

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این سبک یک “حوزه خصوصی واقعی” است به این معنا که حریم خصوصی توسط موتور جاوا اسکریپت در زمان اجرا اعمال می شود.

class Foo {
constructor() {
this.#bar = ‘secret sauce’;
}
}

console.log(new Foo().#bar); // JavaScript error

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در پیکربندی پروژه ما، استفاده اشتباه از هر یک منجر به خطای کامپایل و خط قرمز عصبانی در VSCode می شود.این سوال پیش می آید که از کدام یک استفاده کنیم؟ اگر هر دو کار می کنند و تا آنجا که به ما مربوط می شود یک کار را انجام می دهند، نباید مهم باشد. این (بیشتر) به یک موضوع ترجیح شخصی برمی گردد.

در طول توسعه این پروژه (و سایر پروژه های شخصی) من بر روی قرارداد زیر توافق کرده ام.

class ClickLogger {
#clickCount: number;
get clickCount(): number {
return this.#clickCount;
}

constructor() {
this.#clickCount = 0;

document.body.addEventListener(‘click’, this.#handleClick);
}

private logClickAtLocation(x: number, y: number): void {
this.#clickCount++;

console.log(
`${nth(this.clickCount)} click detected! Clicked at ${x}, ${y}`,
);
}

#handleClick = (e: MouseEvent) => {
this.logClickAtLocation(e.clientX, e.clientY);
};
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه داشته باشید: اجرای nth برای مثال مهم نیست اما به هر حال آن را در زیر آورده ام.

کنوانسیون را می توان به صورت زیر تعریف کرد:

اگر روش محدود است، از ES private استفاده کنید
اگر یک فیلد پشتیبان دارایی است، از ES private استفاده کنید
در غیر این صورت از TypeScript private استفاده کنید

اگر روش محدود است، از ES private استفاده کنید

مقدار بازگردانده شده توسط جاوا اسکریپت this کلمه کلیدی همیشه در زمان نوشتن یک تابع یا روش شناخته شده نیست.این به این دلیل است که مقدار فقط زمانی تنظیم می شود که تابع یا متد فراخوانی شود.بهترین راه برای فکر کردن this به عنوان یک پارامتر مخفی برای هر تابع است و جاوا اسکریپت بسته به نحوه فراخوانی آن تصمیم می گیرد که چه مقداری را در آنجا قرار دهد.

بنابراین وقتی کدی را می نویسید که شبیه این است

function printThis() {
console.log(this);
}

const obj = {
foo: ‘bar’,
printThis,
};

printThis();
obj.printThis();

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چیزی که دریافت می کنید کدی است که به این صورت اجرا می شود*

توجه داشته باشید: این فرض را بر این می‌گذارد که کامپایلر TypeScript شما از “حالت سخت” استفاده می‌کند (در ادامه در مورد آن بیشتر توضیح خواهیم داد)

function printThis(this: unknown) {
console.log(this);
}

const obj = {
foo: ‘bar’,
printThis,
};

printThis(undefined); // logs “undefined”
obj.printThis(obj); // logs “{foo: ‘bar’, printThis: f}”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به طور کلی، ارزش استفاده شده برای this را می توان توسط به سمت چپ نقطه نگاه می کنم. اگر نقطه وجود نداشته باشد، undefined استفاده می شود.

printThis();
\- there’s no dot, so `undefined` is used

obj.printThis()
|-|
– Left of the dot is “obj” so “obj” is passed as `this`

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این برای هر نوع “چپ نقطه” کار می کند.

something().list[4].printThis();

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تبدیل می شود

const _ = something().list[4];
_.printThis(_);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه داشته باشید: something().list[4] فقط یک بار ارزیابی می شود

استثناها: 'استفاده از سختگیرانه':

من در بالا در مورد فرض “حالت دقیق” اشاره کردم. حالت سخت جاوا اسکریپت رفتار را کمی تغییر می دهد. در موردی که “سمت چپ نقطه” وجود ندارد، جاوا اسکریپت در واقع از مقدار استفاده می کند globalThis، که در مرورگرها اشاره ای به جهانی است Window شی فقط در حالت سخت از آن استفاده می کند undefined. تمرین خوبی است که همیشه از حالت سخت استفاده کنید زیرا تعدادی از چیزها را بهینه می کند تا رفتار زمان اجرا را قابل پیش بینی تر و (بنابراین) ایمن تر کند، اما برای کامل بودن، در اینجا یک مثال آورده شده است:

function printStrict() {
‘use strict’;
console.log(this);
}

function printLoose() {
console.log(this);
}

printStrict(); // logs “undefined”
printLoose(); // logs “Window {…}”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همه کدهای موجود در این readme فرض می‌کنند که حالت سخت فعال است.

استثناها: روش های محدود

همچنین امکان بارگذاری یک تابع با مقدار for وجود دارد this (فکر کنید تابع currying) با استفاده از .bind روش

function printThis() {
console.log(this);
}

const message = ‘Abra kadabra’;

const boundPrint = printThis.bind(message);

printThis(); // undefined
boundPrint(); // “Abra kadabra”

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

استثناها: توابع پیکان

یک تابع فلش (با نام مستعار عبارت lambda) از فلش استفاده می کند => توکن برای ایجاد یک تابع ناشناس کوچک.

const printThis = () => console.log(this);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ارزش از this کلمه کلیدی داخل یک تابع فلش تنظیم شده است در لحظه ایجاد تابع. به عبارت دیگر، تقریباً معادل موارد زیر است:

const printThis = function () {
return console.log(this);
}.bind(this);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ارزش از this داخل تابع از هر چیزی که در زمان ایجاد تابع بوده است به ارث می رسد.

حالا که می دانیم چگونه this آثار (درست است؟) می توانم به اصل مطلب برسم… تقریبا.

(بیشتر) توابع Callback به گونه ای فراخوانی می شوند که اختصاص دهند undefined به this. این بدان معنی است که کد زیر کار نخواهد کرد

class ClickLogger {
private clicks = 0;

constructor() {
document.body.addEventListener(‘click’, this.logClick);
}

private logClick() {
this.clicks++;
console.log(`Clicked ${this.clicks} times`);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هنگامی که امیتر رویداد ما را فراخوانی می کند logClick روش این کار را به این صورت انجام می دهد

class EventEmitter {
// …

emitEvent(e) {
for (const handler of this.handlers) {
handler(e);
}
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس وقتی می دویم this.clicks++ ما یک خطا دریافت می کنیم زیرا this دارای ارزش است undefined.

برای رفع این مشکل باید یک متد محدود ایجاد کنیم. سه راه برای انجام این کار وجود دارد:

از یک جدید ساخته شده استفاده کنید .bind روش
document.body.addEventListener(‘click’, this.logClick.bind(this));

این تا حدی لفظی است اما کار می کند.

استفاده مجدد از موجود .bind روش
class ClickLogger {
constructor() {
document.body.addEventListener(‘click’, this.logClick);
}

private logClick = function () {
// …
}.bind(this);
}

این حتی لفظ تر است، اما این مزیت را دارد که می توانید تماس بگیرید document.body.removeEventListener(‘click’, this.logClick) بعدا

از یک تابع پیکان جدید استفاده کنید
document.body.addEventListener(‘click’, (e) => this.logClick(e));

کوتاه ترین تا کنون اما از ناتوانی رنج می برد .removeEventListener مانند مثال 1.

از یک تابع پیکان موجود استفاده کنید
class ClickLogger {
constructor() {
document.body.addEventListener(‘click’, this.logClick);
}

private logClick = () => {
//…
};
}

IMO این یکی تمیزترین است. این روش خیلی طولانی تر از یک روش معمولی نیست، بلکه ارزش آن را نشان می دهد this به دلیل اینکه به عنوان یک تابع فلش تعریف شده است و می توان از آن استفاده کرد .removeEventListener.

اکنون تصمیم گرفته ام که گزینه 4 بالا را دوست دارم، اما یک مشکل دیگر دارم. تشخیص اینکه کدام روش ها مقید هستند و کدام نه آسان نیست:

class ClickLogger {
constructor() {
document.body.addEventListener(‘click’, this.logClick);
document.body.addEventListener(‘keydown’, this.resetCount);
}

// Somewhere else in the file possibly off screen
private logClick = () => {
// …
};

private resetCount() {
// …
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

resetCount مقید نیست؛ اوه، حالا کد شما کار نمی کند.

بنابراین برای متدهای باند من دوست دارم از ES private استفاده کنم # برای و روش‌های بی‌قید من از TypeScript private استفاده می‌کنم. این یک شکل از نشانه گذاری مجارستانی است.

اگر یک فیلد پشتیبان دارایی است، از ES private استفاده کنید

class ClickCounter {
#clickCount: number;

get clickCount() {
return this.#clickCount;
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر دو #clickCount و clickCount داده‌های مشابهی را نشان می‌دهند، اما نمی‌توانیم با TypeScript خصوصی به هر دو نام یکسان بدهیم، زیرا زمانی که کامپایل شد private از بین می رود و در نهایت دو بار همان خاصیت می شود.

class ClickCounter {
private clickCount: number; // error: duplicate identifier

get clickCount() {
return this.clickCount;
} // error: duplicate identifier
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بنابراین اگر باید یک نام جدید کمی متفاوت انتخاب کنیم، چرا نامی را انتخاب نکنیم که با نحوه کار خود جاوا اسکریپت همسو باشد.

در غیر این صورت از TypeScript private استفاده کنید

این مقاله من را به پایان می رساند. ممنون از وقتی که گذاشتید.

تقریباً فراموش کردم که یک تفاوت بین آنها را ذکر کنم private و # هنگام استفاده از Vue

class Counter {
#count: number;
get count() {
return this.#count;
}
increment() {
this.#count++;
}
}

const c = ref(new Counter());

c.value.increment(); // ERROR, cannot access private variable #count from outside the class it was defined in

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Ref ها در Vue مقادیر خود را در a قرار می دهند Proxy شی، بنابراین شما چیزی شبیه به این به نظر می رسد

const c = {
value: new Proxy(new Counter(), {
get: (target, key) => {
return target[key];
},
}),
};

c.value.increment();

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون مقدار “سمت چپ نقطه” در واقع همان است Proxy شیء، نه Counter. این increment سپس تابع بر روی فراخوانی می شود Proxy و از آنجایی که #count خصوصی است برای Counter تلاش برای دسترسی به آن به خطا تبدیل می شود. shallowRef نیز این مشکل را دارد اگر اینطور فکر می کنید می توانید خودتان تصمیم بگیرید Proxies ضد الگو هستند

برای دور زدن این می توانید useRaw(c.value).increment() اما این زشت است و با توجه به آن refs در همه جا استفاده می شود، خسته کننده و پر سر و صدا می شود.

شما همچنین می توانید استفاده کنید private زیرا در سرزمین جاوا اسکریپت private واقعا “خصوصی” نیست.

پایان.

function nth(n: number) {
const str = n.toFixed(0);

if (str.slice(-2, -1) === ‘1’) return `${str}th`;

switch (n % 10) {
case 1:
return `${str}st`;
case 2:
return `${str}nd`;
case 3:
return `${str}rd`;
default:
return `${str}th`;
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مقدمه (با نام مستعار شما می توانید این قسمت را نادیده بگیرید)

چند هفته پیش در محل کار حواس من پرت شد و به طور تصادفی این وبلاگ را به عنوان یک مطلب نوشتم src/readme.md. اکنون که می‌خواهم آن شاخه را در زمان خودش ادغام کنم تا آن readme را حذف کنم، اما دوست دارم فکر کنم که بیش از 4 نفر دیگر در تیم من ممکن است این دیدگاه جالب باشد. بنابراین اکنون آن را همانطور که هست به شما ارائه می کنم. کد نویسی مبارک!

سلام

تصمیم گرفتم قراردادی را که در این پروژه در مورد سبک TypeScript خصوصی و سبک خصوصی ECMAScript استفاده می‌کردم، یادداشت کنم.

class Foo {
    private bar: string;

    constructor() {
        this.bar = 'secret sauce';
    }
}

console.log(new Foo().bar); // TypeScript error
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در TypeScript می توانید از private کلمه کلیدی برای علامت گذاری فیلدها، ویژگی ها و متدها به عنوان “خصوصی” (فقط از داخل همان کلاس قابل دسترسی است).
با این حال، هنگامی که این کد کامپایل شد، این محدودیت دیگر وجود ندارد زیرا private بخشی از جاوا اسکریپت نیست.

بسته به پیکربندی TypeScript شما، کامپایلر هر دو از سوء استفاده از فیلد خصوصی شکایت خواهد کرد. اما هنوز هم کامپایل و کد زیر را منتشر کنید.

class Foo {
    constructor() {
        this.bar = 'secret sauce';
    }
}

console.log(new Foo().bar); // logs "secret sauce"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

گزینه جایگزین استفاده از اصلاح‌کننده خصوصی ECMAScript است که با پیشوند نام با هش انجام می‌شود. #.

class Foo {
    #bar: string;

    constructor() {
        this.#bar = 'secret sauce';
    }
}

console.log(new Foo().#bar); // TypeScript error
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این سبک یک “حوزه خصوصی واقعی” است به این معنا که حریم خصوصی توسط موتور جاوا اسکریپت در زمان اجرا اعمال می شود.

class Foo {
    constructor() {
        this.#bar = 'secret sauce';
    }
}

console.log(new Foo().#bar); // JavaScript error
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در پیکربندی پروژه ما، استفاده اشتباه از هر یک منجر به خطای کامپایل و خط قرمز عصبانی در VSCode می شود.
این سوال پیش می آید که از کدام یک استفاده کنیم؟ اگر هر دو کار می کنند و تا آنجا که به ما مربوط می شود یک کار را انجام می دهند، نباید مهم باشد. این (بیشتر) به یک موضوع ترجیح شخصی برمی گردد.

در طول توسعه این پروژه (و سایر پروژه های شخصی) من بر روی قرارداد زیر توافق کرده ام.

class ClickLogger {
    #clickCount: number;
    get clickCount(): number {
        return this.#clickCount;
    }

    constructor() {
        this.#clickCount = 0;

        document.body.addEventListener('click', this.#handleClick);
    }

    private logClickAtLocation(x: number, y: number): void {
        this.#clickCount++;

        console.log(
            `${nth(this.clickCount)} click detected! Clicked at ${x}, ${y}`,
        );
    }

    #handleClick = (e: MouseEvent) => {
        this.logClickAtLocation(e.clientX, e.clientY);
    };
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه داشته باشید: اجرای nth برای مثال مهم نیست اما به هر حال آن را در زیر آورده ام.

کنوانسیون را می توان به صورت زیر تعریف کرد:

  1. اگر روش محدود است، از ES private استفاده کنید
  2. اگر یک فیلد پشتیبان دارایی است، از ES private استفاده کنید
  3. در غیر این صورت از TypeScript private استفاده کنید

اگر روش محدود است، از ES private استفاده کنید

مقدار بازگردانده شده توسط جاوا اسکریپت this کلمه کلیدی همیشه در زمان نوشتن یک تابع یا روش شناخته شده نیست.
این به این دلیل است که مقدار فقط زمانی تنظیم می شود که تابع یا متد فراخوانی شود.
بهترین راه برای فکر کردن this به عنوان یک پارامتر مخفی برای هر تابع است و جاوا اسکریپت بسته به نحوه فراخوانی آن تصمیم می گیرد که چه مقداری را در آنجا قرار دهد.

بنابراین وقتی کدی را می نویسید که شبیه این است

function printThis() {
    console.log(this);
}

const obj = {
    foo: 'bar',
    printThis,
};

printThis();
obj.printThis();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چیزی که دریافت می کنید کدی است که به این صورت اجرا می شود*

توجه داشته باشید: این فرض را بر این می‌گذارد که کامپایلر TypeScript شما از “حالت سخت” استفاده می‌کند (در ادامه در مورد آن بیشتر توضیح خواهیم داد)

function printThis(this: unknown) {
    console.log(this);
}

const obj = {
    foo: 'bar',
    printThis,
};

printThis(undefined); // logs "undefined"
obj.printThis(obj); // logs "{foo: 'bar', printThis: f}"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به طور کلی، ارزش استفاده شده برای this را می توان توسط به سمت چپ نقطه نگاه می کنم. اگر نقطه وجود نداشته باشد، undefined استفاده می شود.

printThis();
\- there's no dot, so `undefined` is used

obj.printThis()
|-|
   - Left of the dot is "obj" so "obj" is passed as `this`
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این برای هر نوع “چپ نقطه” کار می کند.

something().list[4].printThis();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تبدیل می شود

const _ = something().list[4];
_.printThis(_);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه داشته باشید: something().list[4] فقط یک بار ارزیابی می شود

استثناها: 'استفاده از سختگیرانه':

من در بالا در مورد فرض “حالت دقیق” اشاره کردم. حالت سخت جاوا اسکریپت رفتار را کمی تغییر می دهد. در موردی که “سمت چپ نقطه” وجود ندارد، جاوا اسکریپت در واقع از مقدار استفاده می کند globalThis، که در مرورگرها اشاره ای به جهانی است Window شی فقط در حالت سخت از آن استفاده می کند undefined. تمرین خوبی است که همیشه از حالت سخت استفاده کنید زیرا تعدادی از چیزها را بهینه می کند تا رفتار زمان اجرا را قابل پیش بینی تر و (بنابراین) ایمن تر کند، اما برای کامل بودن، در اینجا یک مثال آورده شده است:

function printStrict() {
    'use strict';
    console.log(this);
}

function printLoose() {
    console.log(this);
}

printStrict(); // logs "undefined"
printLoose(); // logs "Window {...}"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همه کدهای موجود در این readme فرض می‌کنند که حالت سخت فعال است.

استثناها: روش های محدود

همچنین امکان بارگذاری یک تابع با مقدار for وجود دارد this (فکر کنید تابع currying) با استفاده از .bind روش

function printThis() {
    console.log(this);
}

const message = 'Abra kadabra';

const boundPrint = printThis.bind(message);

printThis(); // undefined
boundPrint(); // "Abra kadabra"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

استثناها: توابع پیکان

یک تابع فلش (با نام مستعار عبارت lambda) از فلش استفاده می کند => توکن برای ایجاد یک تابع ناشناس کوچک.

const printThis = () => console.log(this);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ارزش از this کلمه کلیدی داخل یک تابع فلش تنظیم شده است در لحظه ایجاد تابع. به عبارت دیگر، تقریباً معادل موارد زیر است:

const printThis = function () {
    return console.log(this);
}.bind(this);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ارزش از this داخل تابع از هر چیزی که در زمان ایجاد تابع بوده است به ارث می رسد.

حالا که می دانیم چگونه this آثار (درست است؟) می توانم به اصل مطلب برسم… تقریبا.

(بیشتر) توابع Callback به گونه ای فراخوانی می شوند که اختصاص دهند undefined به this. این بدان معنی است که کد زیر کار نخواهد کرد

class ClickLogger {
    private clicks = 0;

    constructor() {
        document.body.addEventListener('click', this.logClick);
    }

    private logClick() {
        this.clicks++;
        console.log(`Clicked ${this.clicks} times`);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هنگامی که امیتر رویداد ما را فراخوانی می کند logClick روش این کار را به این صورت انجام می دهد

class EventEmitter {
    // ...

    emitEvent(e) {
        for (const handler of this.handlers) {
            handler(e);
        }
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس وقتی می دویم this.clicks++ ما یک خطا دریافت می کنیم زیرا this دارای ارزش است undefined.

برای رفع این مشکل باید یک متد محدود ایجاد کنیم. سه راه برای انجام این کار وجود دارد:

  1. از یک جدید ساخته شده استفاده کنید .bind روش

    document.body.addEventListener('click', this.logClick.bind(this));
    

    این تا حدی لفظی است اما کار می کند.

  2. استفاده مجدد از موجود .bind روش

    class ClickLogger {
        constructor() {
            document.body.addEventListener('click', this.logClick);
        }
    
        private logClick = function () {
            // ...
        }.bind(this);
    }
    

    این حتی لفظ تر است، اما این مزیت را دارد که می توانید تماس بگیرید document.body.removeEventListener('click', this.logClick) بعدا

  3. از یک تابع پیکان جدید استفاده کنید

    document.body.addEventListener('click', (e) => this.logClick(e));
    

    کوتاه ترین تا کنون اما از ناتوانی رنج می برد .removeEventListener مانند مثال 1.

  4. از یک تابع پیکان موجود استفاده کنید

    class ClickLogger {
        constructor() {
            document.body.addEventListener('click', this.logClick);
        }
    
        private logClick = () => {
            //...
        };
    }
    

    IMO این یکی تمیزترین است. این روش خیلی طولانی تر از یک روش معمولی نیست، بلکه ارزش آن را نشان می دهد this به دلیل اینکه به عنوان یک تابع فلش تعریف شده است و می توان از آن استفاده کرد .removeEventListener.

اکنون تصمیم گرفته ام که گزینه 4 بالا را دوست دارم، اما یک مشکل دیگر دارم. تشخیص اینکه کدام روش ها مقید هستند و کدام نه آسان نیست:

class ClickLogger {
    constructor() {
        document.body.addEventListener('click', this.logClick);
        document.body.addEventListener('keydown', this.resetCount);
    }

    // Somewhere else in the file possibly off screen
    private logClick = () => {
        // ...
    };

    private resetCount() {
        // ...
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

resetCount مقید نیست؛ اوه، حالا کد شما کار نمی کند.

بنابراین برای متدهای باند من دوست دارم از ES private استفاده کنم # برای و روش‌های بی‌قید من از TypeScript private استفاده می‌کنم. این یک شکل از نشانه گذاری مجارستانی است.

اگر یک فیلد پشتیبان دارایی است، از ES private استفاده کنید

class ClickCounter {
    #clickCount: number;

    get clickCount() {
        return this.#clickCount;
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر دو #clickCount و clickCount داده‌های مشابهی را نشان می‌دهند، اما نمی‌توانیم با TypeScript خصوصی به هر دو نام یکسان بدهیم، زیرا زمانی که کامپایل شد private از بین می رود و در نهایت دو بار همان خاصیت می شود.

class ClickCounter {
    private clickCount: number; // error: duplicate identifier

    get clickCount() {
        return this.clickCount;
    } // error: duplicate identifier
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بنابراین اگر باید یک نام جدید کمی متفاوت انتخاب کنیم، چرا نامی را انتخاب نکنیم که با نحوه کار خود جاوا اسکریپت همسو باشد.

در غیر این صورت از TypeScript private استفاده کنید

این مقاله من را به پایان می رساند. ممنون از وقتی که گذاشتید.

تقریباً فراموش کردم که یک تفاوت بین آنها را ذکر کنم private و # هنگام استفاده از Vue

class Counter {
    #count: number;
    get count() {
        return this.#count;
    }
    increment() {
        this.#count++;
    }
}

const c = ref(new Counter());

c.value.increment(); // ERROR, cannot access private variable #count from outside the class it was defined in
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Ref ها در Vue مقادیر خود را در a قرار می دهند Proxy شی، بنابراین شما چیزی شبیه به این به نظر می رسد

const c = {
    value: new Proxy(new Counter(), {
        get: (target, key) => {
            return target[key];
        },
    }),
};

c.value.increment();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون مقدار “سمت چپ نقطه” در واقع همان است Proxy شیء، نه Counter. این increment سپس تابع بر روی فراخوانی می شود Proxy و از آنجایی که #count خصوصی است برای Counter تلاش برای دسترسی به آن به خطا تبدیل می شود. shallowRef نیز این مشکل را دارد اگر اینطور فکر می کنید می توانید خودتان تصمیم بگیرید Proxies ضد الگو هستند

برای دور زدن این می توانید useRaw(c.value).increment() اما این زشت است و با توجه به آن refs در همه جا استفاده می شود، خسته کننده و پر سر و صدا می شود.

شما همچنین می توانید استفاده کنید private زیرا در سرزمین جاوا اسکریپت private واقعا “خصوصی” نیست.

پایان.

function nth(n: number) {
    const str = n.toFixed(0);

    if (str.slice(-2, -1) === '1') return `${str}th`;

    switch (n % 10) {
        case 1:
            return `${str}st`;
        case 2:
            return `${str}nd`;
        case 3:
            return `${str}rd`;
        default:
            return `${str}th`;
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا