برنامه نویسی

نمونه اولیه JavaScript و __proto__ – آیا می دانید چگونه کار می کند؟

tl ؛ دکتر:

در جاوا اسکریپت ، همه وراثت است نمونه اولیه – به این معنی که هر شیء از طریق یک زنجیره به نام از شیء دیگر به ارث می برد __proto__بشر در پشت صحنه ، حتی کلاس ها و آرایه ها به این مکانیسم متکی هستند. این پست چه چیزی را تجزیه می کند __proto__ وت prototype واقعاً ، چگونه آنها متفاوت هستند ، چگونه زنجیره های وراثت تشکیل می شوند و چگونه سازندگان رفتار را پایین می آورند. اگر تا به حال در مورد نحوه اشتراک اشیاء یا چرا می توانید از آن استفاده کنید toString() در مورد همه چیز – این یکی برای شما است.


مقدمه

خوش آمدید قسمت 2 سریال “آیا می دانید چگونه کار می کند؟”

اگر در حال دنبال کردن هستید ، به یاد خواهید آورد که همه چیز شروع شد وقتی که من یک پست نوشتم توابع فلش (که معلوم شد قسمت 0). پاسخ به آن پست – پر از سوالات روشنگری – باعث شد من متوجه شوم که بسیاری از شیاطین هنوز در مورد آن مطمئن نیستند مکانیک اصلی از جاوا اسکریپت.

بنابراین ما در اینجا هستیم ، در ادامه سفر.

موضوع امروز یکی از سوء تفاهم ترین جنبه های جاوا اسکریپت است: تفاوت بین __proto__ وت prototypeبشر

اگر تا به حال فکر کرده اید:

  • چرا اشیاء شما می توانند استفاده کنند .toString() حتی اگر هرگز آن را تعریف نکرده اید ،
  • چه اتفاقی می افتد هنگام استفاده class، یا
  • چه Array.prototype در واقع یعنی …

سپس این پست برای شما مناسب است. بیایید به واقعی مکانیک وراثت جاوا اسکریپت.


همانطور که در موضوع وراثت دیدیم ، جاوا اسکریپت در مقایسه با سایر زبانهای برنامه نویسی ، وراثت را متفاوت می کند. ما در مورد صحبت می کنیم ارث اولیهبشر اما این در عمل به چه معنی است؟ بیایید نگاهی دقیق تر بیندازیم.

const person = {};
console.log(person); // Object { __proto__: Object }
حالت تمام صفحه را وارد کنید

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

در اینجا ، ما خالی اعلام می کنیم person شیء. اما اگر محتوای آن را بازرسی کنیم ، می بینیم که واقعاً خالی نیست – حاوی یک __proto__ ویژگی (گاهی به عنوان نشان داده شده است در مرورگر) ، حتی اگر ما صریحاً آن را اعلام نکردیم.

خوب ، برای درک این موضوع ، ما باید کمی عمیق تر پیش برویم. بیایید این کار را انجام دهیم:

person.name = "Alan Turing";
person.age = 41;
console.log(person.name); // Alan Turing
console.log(person.age); // 41
console.log(person.nationality); // undefined
console.log(person.speak); // undefined
حالت تمام صفحه را وارد کنید

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

نتایج در اینجا همانطور که انتظار می رود – هر آنچه که ما صریحاً بازده را تعریف نکردیم undefinedبشر اما استثنائاتی وجود دارد:

person.toString; // function toString();
person.valueOf; // function valueOf();
حالت تمام صفحه را وارد کنید

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

حتی اگر ما این کارکردها را تعریف نکردیم ، آنها برنمی گردند undefinedبشر در واقع ، اگر آنها را اجرا کنیم ، آنها نتیجه می گیرند. اما چرا این است؟ آنها از کجا آمده اند؟

__proto__

در واقع ، هر وقت متغیر یا ثابت را با یک شیء به عنوان مقدار آن اعلام می کنیم – مهم نیست که چگونه ایجاد شده است (const obj = {}با const obj = new Object()، یا Object.create({})) – همیشه یک __proto__ خاصیت این همه چیزهایی را که شیء به عنوان نمونه ای از آن به ارث می برد نگه می دارد اعتراض (سرمایه O).

این منحصر به اشیاء نیست. بسته به نوع متغیر ایجاد شده ، آن را از یک متفاوت به ارث می برد سازندهبشر سازندگان اساساً پایه های جاوا اسکریپت هستند – آنچه از هر نوع ساخته شده است.

به عنوان مثال:

const cars = [];
console.log(cars); // Array [length: 0, __proto__: Array[]]
حالت تمام صفحه را وارد کنید

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

هنگام ایجاد یک آرایه ، می توانیم از قبل ببینیم که دارای برخی از ویژگی های خاص است: a length ویژگی ، و آن __proto__ است ، Array[]بشر این بدان معنی است که با استفاده از Array سازنده ، که تعریف می کند که آرایه ها دارای یک هستند length و برخی از روش های داخلی

cars.push("Aston Martin");
console.log(cars.length); // 1
console.log(cars.pop());  // Aston Martin
console.log(cars.length); // 0
حالت تمام صفحه را وارد کنید

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

به همین دلیل می توانیم از روش هایی مانند استفاده کنیم Array.push() وت Array.pop()بشر و به همین دلیل است که مستندات اغلب این روشها را با پیشوند نشان می دهد Array.– آنها روشهای Array کلاس که همه آرایه ها از آن به ارث می برند.

اما __proto__ منحصر به انواع پیچیده مانند اشیاء ، آرایه ها یا مجموعه ها نیست. هر نوع در جاوا اسکریپت توسط یک نمونه اولیه تعریف می شود.

const fruit = "Banana";
console.log(fruit.__proto__); // String { "" }

const number = 10;
console.log(number.__proto__); // Number { 0 }

const boolean = true;
console.log(boolean.__proto__); // Boolean { false }
حالت تمام صفحه را وارد کنید

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

همه انواع ابتدایی سازه های خاص خود را دارند و ویژگی ها و روش های خاص خود را به ارث می برند. همچنین ، در داخل خروجی سازنده ، اغلب مقداری در بریس های فرفری مانند مشاهده می کنید. "" با 0، یا false – این مقدار پیش فرض اولیه آن نوع را نشان می دهد.

بنابراین ، اگر ما با استفاده از آن سازندگان بدون عبور از هر مقدار متغیر ایجاد کنیم ، با آن پیش فرض ابتدایی آغاز می شود:

const stringTest = new String();
const numberTest = new Number();
const boolTest = new Boolean();

console.log(stringTest.valueOf()); // ""
console.log(numberTest.valueOf()); // 0
console.log(boolTest.valueOf());   // false
حالت تمام صفحه را وارد کنید

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

حتی جالب تر ، هر یک از این سازندگان (رشته ، شماره ، بولی و غیره) نیز خاص خود را دارند __proto__بشر

const someVar = "";
console.log(someVar.__proto__.__proto__); // Object { }
حالت تمام صفحه را وارد کنید

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

وقتی آخرین بار را باز می کنیم __proto__، می بینیم که این همان چیزی است که هنگام ایجاد یک شیء خالی ساده به دست می آوریم. بنابراین می توانیم نتیجه بگیریم: String وراثت از Object، و یک متغیر ایجاد شده از String وراثت از Stringبشر

این تأیید می کند که حتی انواع مانند رشته در نهایت از شیء به ارث می برند و تشکیل می دهند __proto__ زنجیره ای (به نام زنجیره نمونه اولیه) که همیشه به ریشه جاوا اسکریپت باز می گردد: Objectبشر بیایید این مفهوم را کشف کنیم:

const being = {
  type: "Living Being"
};

const species = Object.create(being);
species.name = "Human";

const person = Object.create(species);
person.age = 25;

console.log(person);
/* 
Object { 
  age: 25,
  __proto__: Object { 
    name: "Human",
    __proto__: Object {
      type: "Living Being",
      __proto__: Object {...}
    }
  }
}
*/
حالت تمام صفحه را وارد کنید

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

هنگام بازرسی person شی ، ما می بینیم که همه چیز را از آن به ارث می برد species (که به عنوان یک طرح استفاده می شد) و از being (برای ایجاد استفاده می شود species) – و در نهایت از Objectبشر

بیایید کمی بیشتر برویم:

const person2 = Object.create(species);
person2.name = "Dwight";

console.log(person.name);  // Human
console.log(person2.name); // Dwight
حالت تمام صفحه را وارد کنید

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

هنگام چاپ person.name، ما از “انسان” می گیریم species.nameبشر اما person2.name “دویت” است ، حتی اگر از آن ایجاد شده باشد speciesبشر

به این دلیل است که person2 خودش را دریافت کرد name ویژگی وقتی تماس می گیریم person.name، این شیء خود را جستجو می کند ، چیزی پیدا نمی کند و به پایین می رود __proto__ زنجیره ای برای به دست آوردن ارزش. اما person2 در حال حاضر یک name، بنابراین در آنجا متوقف می شود.

console.log(person2);
/*
Object {
  name: "Dwight",
  __proto__: Object {
    name: "Human",
    __proto__: Object {...}
  }
}
*/
حالت تمام صفحه را وارد کنید

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

اگر می خواستیم name از species با استفاده از person2 به عنوان یک مرجع ، ما باید نام آن را تغییر دهیم __proto__بشر این تغییر خواهد کرد species.name و تمام اشیاء ارثی از آن را تحت تأثیر قرار می دهد.

person2.__proto__.name = "Elf";
console.log(person.name);    // Elf
console.log(species.name);   // Elf
حالت تمام صفحه را وارد کنید

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


این همچنین با کلاس ها کار می کند

class Vehicle {
  move() {
    return "Moving";
  }
}

class Car extends Vehicle {
  accelerate() {
    return "Vroom";
  }
}

class RaceCar extends Car {
  compete() {
    return "Jump Start!";
  }
}

const mclaren = new RaceCar();

console.log(mclaren); // Object { }

mclaren.move();       // "Moving"
mclaren.accelerate(); // "Vroom"
mclaren.compete();   // "Jump Start!"
mclaren.winRace();    // undefined
حالت تمام صفحه را وارد کنید

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

اگر بازرسی کنیم mclaren، در سطح بالا می بینیم که از آن ایجاد شده است RaceCar سازنده آن را __proto__ است ، Car، و سطح بعدی Vehicle، و سرانجام Objectبشر چیزی شبیه به این:

زنجیره تیپ

همچنین ، mclaren می تواند همه کارها را انجام دهد RaceCarبا Carوت Vehicle می تواند انجام دهد اما اگر سعی کنیم به چیزی دسترسی پیدا کنیم که در هیچ کجای آن وجود ندارد زنجیره ارث، ما می گیریم undefinedبشر


prototype

بیایید تنظیم کنیم __proto__ گذشته برای یک ثانیه. چیست prototype و چگونه متفاوت است؟

دیدن چیزی شبیه به Array.prototype.concat() در اسناد اما دقیقاً چیست prototype؟

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

این را بررسی کنید:

function Person(name) {
  this.name = name;
}

const person = new Person("Michael Jackson");

console.log(person); // Object { name: "Michael Jackson" }

person.__proto__ === Person.prototype; // true
حالت تمام صفحه را وارد کنید

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

آنچه در اینجا می بینیم این است که Person(name) تابع نحوه ساخت یک شی را مشخص می کند. در این حالت ، ما عبور می کنیم name پارامتر برای تولید a Person شیء.

همچنین ، ما می توانیم مشاهده کنیم که یک کلاس prototype به عنوان به شیء منتقل می شود __proto__بشر بنابراین ، اگر چیزی را در نمونه اولیه کلاس اضافه یا اصلاح کنیم ، این تغییر در تمام اشیاء آن کلاس منعکس می شود.

برعکس نیز درست است – اصلاح __proto__ از یک نمونه می تواند در نمونه اولیه کلاس و در همه موارد دیگر تأمل کند.

در اصل ، __proto__ وت prototype به همان شیء مراجعه کنید – فقط به روش های مختلف دسترسی پیدا کنید.

اما به طور خلاصه ، این تفاوت ها هستند:

__proto__

→ روی وجود دارد هر نمونه شی

→ به شیئی که از آن به ارث می برد اشاره می کند

→ استفاده شده در زمان اجرا برای رفع خصوصیات و روشهای زنجیره وراثت

→ شما به ندرت این را به صورت دستی تنظیم می کنید (اگرچه امکان پذیر است)

prototype

→ فقط در توابع و کلاسهای سازنده

that تعریف موارد جدید ایجاد شده با new ارث می برد

→ شما از آن استفاده می کنید روشهای مشترک را اضافه یا نادیده بگیرید

→ می شود __proto__ از مواردی که توسط آن سازنده ایجاد شده است

افکار نهایی

درک __proto__ وت prototype گامی بزرگ برای تسلط بر نحوه کار JavaScript در زیر کاپوت است. این فقط تئوری نیست-این ستون فقرات نحوه ارتباط اشیاء ، رفتار وراثت و کارآمد در حافظه است.

این که آیا شما با اشیاء ساده کار می کنید ، از کلاس ها استفاده می کنید ، یا چیزی را با چارچوب هایی مانند React یا Vue ایجاد می کنید ، این مفهوم همیشه وجود دارد – سکوت کد خود را.

نکته من؟

با این مفاهیم آزمایش کنید ، اشیاء خود را در کنسول مرورگر بازرسی کنید و با استفاده از زنجیرهای میراث خود را بسازید Object.create()بشر شما تعجب خواهید کرد که JavaScript چقدر واضح تر می شود پس از کلیک بر روی این لایه “نامرئی”.


actions سؤال ، بینش یا موارد استفاده جالب برای نمونه های اولیه دارید؟

نظر زیر را رها کنید – دوست دارم از شما بشنوم!

👉 و اگر از این سریال لذت می برید ، مرا دنبال کنید Matheusjulidori برای گرفتن قسمت های بعدی!

بعدی: توابع سازنده

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

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

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

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