مقدمة غنائية
بعد أن تلقيت مرة أخرى مجموعة من الأسئلة حول النماذج الأولية في المقابلة التالية ، أدركت أنني نسيت قليلاً تعقيدات النماذج الأولية ، وقررت تحديث معلوماتي. صادفت مجموعة من المقالات التي كتبت إما بإلهام من المؤلف ، أو كيف "يشعر" بالنماذج الأولية ، أو أن المقالة تدور حول جزء منفصل من الموضوع ولم تقدم صورة كاملة لما كان يحدث.
اتضح أن هناك الكثير من الأشياء غير الواضحة من الأيام الخوالي لـ ES5 وحتى ES6 التي لم أسمع بها. كما اتضح أن إخراج وحدة تحكم المتصفح قد لا يتوافق مع الواقع.
ما هو النموذج الأولي
الكائن في JS له خصائصه الخاصة والموروثة ، على سبيل المثال ، في هذا الكود:
var foo = { bar: 1 };
foo.bar === 1 // true
typeof foo.toString === "function" // true
الكائن fooله خاصية خاصة به barذات قيمة 1، ولكن له أيضًا خصائص أخرى مثل toString. لفهم كيفية fooحصول الكائن على خاصية جديدة toString، دعنا نلقي نظرة على ما يتكون منه الكائن:
النقطة هي أن الكائن لديه إشارة إلى كائن نموذج أولي آخر. عند الوصول إلى حقل foo.toString، يتم إجراء البحث عن هذه الخاصية أولاً من الكائن نفسه ، ثم من النموذج الأولي للنموذج الأولي للنموذج الأولي الخاص به ، وما إلى ذلك حتى تنتهي سلسلة النموذج الأولي. إنها مثل قائمة كائنات مرتبطة بشكل فردي ، حيث يتم فحص الكائن وكائنات النموذج الأولي الخاص به بدوره. هذه هي الطريقة التي يتم بها تنفيذ وراثة الخصائص ، على سبيل المثال ، (تقريبًا ، ولكن أكثر من ذلك لاحقًا) أي كائن له طرق valueOfو toString.
, constructor __proto__. constructor -, , __proto__ ( null, ). ., .
constructor
constructor – , :
const a = {};
a.constructor === Object // true
, , :
object.constructor(object.arg)
, , , . constructor , writable , , , .
, , JS . , , [[SlotName]]. [[Prototype]] - ( null, ).
- , [[Prototype]] JS , . , __proto__, , JS .
,
__proto__ [[Prototype]] Object.prototype:
- __proto__ . __proto__ , . __proto__ :
const foo = {};
foo.toString(); // toString() Object.prototype '[object Object]',
foo.__proto__ = null; // null
foo.toString(); // TypeError: foo.toString is not a function
foo.__proto__ = Object.prototype; //
foo.toString(); // , TypeError: foo.toString is not a function
? , __proto__ – Object.prototype, foo. - Object.prototype, __proto__ .
. :
var baz = { test: "test" };
var foo = { bar: 1 };
foo.__proto__ = baz;
Chrome foo :
baz Object.prototype:
baz.__proto__ = null;
Chrome :
Object.prototype baz __proto__ undefined foo, Chrome __proto__ . [[Prototype]], __proto__, , .
: .
: __proto__ Object.setPrototypeOf.
var myProto = { name: "Jake" };
var foo = {};
Object.setPrototypeOf(foo, myProto);
foo.__proto__ = myProto;
, , .
[[Extensible]] , . , false : Object.freeze, Object.seal, Object.preventExtensions. :
const obj = {};
Object.preventExtensions(obj);
Object.setPrototypeOf(obj, Function.prototype); // TypeError: #<Object> is not extensible
. .
:
const foo = Object.create(myPrototype);
Object.create, __proto__:
const foo = { __proto__: myPrototype };
:
const f = function () {}
f.prototype = myPrototype;
const foo = new f();
new, . , new prototype , .. [[Prototype]], .
.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const user = new Person('John', 'Doe');
Person , :
Person.prototype? , prototype (note 3), prototype , . , :
Person.prototype.fullName = function () {
return this.firstName + ' ' + this.lastName;
}
user.fullName() "John Doe".
new
new . new :
- self
- prototype self
- self this
- self ,
, new :
function custom_new(constructor, args) {
// https://stackoverflow.com/questions/31538010/test-if-a-variable-is-a-primitive-rather-than-an-object
function isPrimitive(val) {
return val !== Object(val);
}
const self = Object.create({});
const constructorValue = constructor.apply(self, args) || self;
return isPrimitive(constructorValue) ? self : constructorValue;
}
custom_new(Person, ['John', 'Doe'])
ES6 new new.target, , new, :
function Foo() {
console.log(new.target === Foo);
}
Foo(); // false
new Foo(); // true
new.target undefined , new;
, Student Person.
- Student Person
- `Student.prototype` `Person`
- `Student.prototype`
function Student(firstName, lastName, grade) {
Person.call(this, firstName, lastName);
this.grade = grade;
}
// 1
Student.prototype = Object.create(Person.prototype, {
constructor: {
value:Student,
enumerable: false,
writable: true
}
});
// 2
Object.setPrototypeOf(Student.prototype, Person.prototype);
Student.prototype.isGraduated = function() {
return this.grade === 0;
}
const student = new Student('Judy', 'Doe', 7);
( , .. this ), ( )
1 , .. Object.setPrototypeOf .
, , Person Student:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
fullName() {
return this.firstName + ' ' + this.lastName;
}
}
class Student extends Person {
constructor(firstName, lastName, grade) {
super(firstName, lastName);
this.grade = grade;
}
isGraduated() {
return this.grade === 0;
}
}
, :
- , new
-
prototype .
P.S.
سيكون من السذاجة توقع أن تجيب مقالة واحدة على جميع الأسئلة. إذا كانت لديك أسئلة مثيرة للاهتمام ، أو رحلات إلى التاريخ ، أو عبارات منطقية أو لا أساس لها من أنني فعلت كل شيء خاطئ ، أو تصحيحات للأخطاء ، فاكتب في التعليقات.