Pengantar liris
Setelah sekali lagi menerima banyak pertanyaan tentang prototipe pada wawancara berikutnya, saya menyadari bahwa saya telah sedikit melupakan kerumitan pembuatan prototipe, dan memutuskan untuk menyegarkan pengetahuan saya. Saya menemukan banyak artikel yang ditulis baik atas inspirasi penulis, bagaimana dia "merasakan" prototipe, atau artikel tentang bagian terpisah dari topik dan tidak memberikan gambaran lengkap tentang apa yang terjadi.
Ternyata banyak hal yang tidak kentara dari ES5 dulu bahkan ES6 yang belum pernah saya dengar. Ternyata output dari konsol browser mungkin tidak sesuai dengan kenyataan.
Apa itu prototipe
Objek di JS memiliki properti sendiri dan mewarisi, misalnya, dalam kode ini:
var foo = { bar: 1 };
foo.bar === 1 // true
typeof foo.toString === "function" // true
objek foomemiliki properti sendiri bardengan nilai 1, tetapi juga memiliki properti lain seperti toString. Untuk memahami bagaimana sebuah objek foomendapatkan properti baru toString, mari kita lihat terdiri dari apa objek tersebut:
Intinya adalah suatu objek memiliki referensi ke objek prototipe lain. Saat mengakses bidang foo.toString, pencarian properti semacam itu pertama-tama dilakukan dari objek itu sendiri, lalu dari prototipe, prototipe prototipe, dan seterusnya sampai rantai prototipe berakhir. Ini seperti daftar objek yang tertaut tunggal, di mana objek dan objek prototipenya diperiksa secara bergantian. Ini adalah bagaimana pewarisan properti diimplementasikan, misalnya, (hampir, tetapi lebih dari itu nanti) objek apapun memiliki metode valueOfdan 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.
Naif jika mengharapkan satu artikel menjawab semua pertanyaan. Jika Anda memiliki pertanyaan menarik, perjalanan ke dalam sejarah, pernyataan yang beralasan atau tidak berdasar bahwa saya melakukan kesalahan, atau mengoreksi kesalahan, tulis di komentar.