プロトタイプとプロトタイプの継承
1.プロトタイプ継承
開発の過程で、既存の機能を導入して拡張する必要がある場合があります.
たとえば、user
という名前のオブジェクトがこのuser
とよく似ていますが、少し異なるオブジェクトを作成する必要がある場合、どの方法が最も効果的ですか?
1つの方法は、プロトタイプ継承(プロトタイプ継承)です.
[[prototype]]
JavaScriptのオブジェクトには、[[prototype]]
という非表示プログラムがあります.
この値はnull
または他のオブジェクトへの参照です.他のオブジェクトをロックすると、参照オブジェクトは「プロトタイプ」と呼ばれます.
プロトタイプの興味深い点は、上図object
でpropertyを読みたいということであり、そのpropertyがなければ自動的にpropertyでpropertyを検索する
プログラミングではこの動作をprototypal inheritance
と呼ぶ.[[prototype]]
は非表示のプログラムですが、開発者は様々な方法で値を設定できます.そのために__proto__
を使用します.let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal;
__proto__
は[[prototype]]
のgetter-setter
すなわち、__proto__ === [[prototype]]
ではなく、値の取得または変更のみが可能である.
最近の値は、__proto__
ではなくObject.getPrototypeOf
です.Object.setPrototypeOf
を使用して値を設定
⚠(ただし互換性の問題で⚜4|を使用する場合が多い)
上記の例では、__proto__
にはrabbit
はありませんが、これをプロトタイプeats: true
に設定することで、そのオブジェクトからプロトタイプをインポートできます.let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal; // (*)
// 프로퍼티 eats과 jumps를 rabbit에서도 사용할 수 있게 되었습니다.
alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true
この方法も当てはまるlet animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// 메서드 walk는 rabbit의 프로토타입인 animal에서 상속받았습니다.
rabbit.walk(); // 동물이 걷습니다.
プロトタイプの深さは無限に深くすることができますが、推奨されません.let animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
let longEar = {
earLength: 10,
__proto__: rabbit
};
// 메서드 walk는 프로토타입 체인을 통해 상속받았습니다.
longEar.walk(); // 동물이 걷습니다.
alert(longEar.jumps); // true (rabbit에서 상속받음)
プロトタイプフィルタにはいくつかの制限があります.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal;
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal; // (*)
// 프로퍼티 eats과 jumps를 rabbit에서도 사용할 수 있게 되었습니다.
alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true
let animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// 메서드 walk는 rabbit의 프로토타입인 animal에서 상속받았습니다.
rabbit.walk(); // 동물이 걷습니다.
let animal = {
eats: true,
walk() {
alert("동물이 걷습니다.");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
let longEar = {
earLength: 10,
__proto__: rabbit
};
// 메서드 walk는 프로토타입 체인을 통해 상속받았습니다.
longEar.walk(); // 동물이 걷습니다.
alert(longEar.jumps); // true (rabbit에서 상속받음)
つまり、他のオブジェクトを閉じた形式で参照すると、エラー
animal
の値はオブジェクト__proto__
のみであり、他のデータ型null
すなわち、2つのオブジェクトを同時に継承することはできないconst animal = {
walk: true
}
const human = {
talk: true
}
const ayaan = {
eat: true
}
ayaan.__proto__ = animal;
console.log(ayaan.walk); // true
// 하나의 객체만 상속받을 수 있음
ayaan.__proto__ = human;
console.log(ayaan.walk); // undefined
console.log(ayaan.talk); // true
// 순환 참조
human.__proto__ = animal;
animal.__proto__ = ayaan;
// VM570:1 Uncaught TypeError: Cyclic __proto__ value
「原型は読み取り専用」という言葉を必ず覚えておきましょう.プロトタイプは、プロトタイプを読むときにのみ使用されます.
つまり、Propertyを追加、変更または削除する演算は、オブジェクトに直接行わなければなりません.
また、prototypeは、継承されたオブジェクトに対応するpropertyがない場合にのみ継承されます.
let animal = {
eats: true,
walk() {
/* rabbit은 이제 이 메서드를 사용하지 않습니다. */
}
};
let rabbit = {
__proto__: animal
};
rabbit.walk = function() {
alert("토끼가 깡충깡충 뜁니다.");
};
rabbit.walk(); // 토끼가 깡충깡충 뜁니다.
しかし、アクセス者プログラム(accessor property)では、動作が少し異なります.
let user = {
name: "John",
surname: "Smith",
set fullName(value) {
[this.name, this.surname] = value.split(" ");
},
get fullName() {
return `${this.name} ${this.surname}`;
}
};
let admin = {
__proto__: user,
isAdmin: true
};
alert(admin.fullName); // John Smith (*)
// setter 함수가 실행됩니다!
admin.fullName = "Alice Cooper"; // (**)
alert(admin.fullName); // Alice Cooper, setter에 의해 추가된 admin의 프로퍼티(name, surname)에서 값을 가져옴
alert(user.fullName); // John Smith, 본래 user에 있었던 프로퍼티 값
上記のコードを理解するには、[[prototype]]
をもっと理解する必要があるようです.2. this
上記の例では、this
にはどのような値が含まれていますか?
結論から言えば、this
の原型は影響を受けない.this
は、オブジェクトからメソッドを呼び出すか、プロトタイプからメソッドを呼び出すかにかかわらず、this
は常に.
の前のオブジェクトを表します.
例えば、上でsetter関数をadmin.fullName = ...
で呼び出した場合、this
はadmin
である
これらのプロパティは、巨大なオブジェクトを作成し、ここで多くの方法を継承すると簡単に使用できます.
例えば、メソッド・リポジトリとして機能するオブジェクトanimal
rabbit
が継承される.// animal엔 다양한 메서드가 있습니다.
let animal = {
walk() {
if (!this.isSleeping) {
alert(`동물이 걸어갑니다.`);
}
},
sleep() {
this.isSleeping = true;
}
};
let rabbit = {
name: "하얀 토끼",
__proto__: animal
};
// rabbit에 새로운 프로퍼티 isSleeping을 추가하고 그 값을 true로 변경합니다.
rabbit.sleep();
alert(rabbit.isSleeping); // true
alert(animal.isSleeping); // undefined (프로토타입에는 isSleeping이라는 프로퍼티가 없습니다.)
「メソッドを共有したいがオブジェクトのステータスを共有しない場合は、このオプションを使用します」for...in
繰り返し文を使用すると、継承されたプログラムも巡回オブジェクトに含まれます.let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
// Object.keys는 객체 자신의 키만 반환합니다.
alert(Object.keys(rabbit)); // jumps
// for..in은 객체 자신의 키와 상속 프로퍼티의 키 모두를 순회합니다.
for(let prop in rabbit) alert(prop); // jumps, eats
obj.hasOwnProperty(key)
booleanvalueを使用して、継承されたpropertyか自分のpropertyかを決定します.let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
for(let prop in rabbit) {
let isOwn = rabbit.hasOwnProperty(prop);
if (isOwn) {
alert(`객체 자신의 프로퍼티: ${prop}`); // 객체 자신의 프로퍼티: jumps
} else {
alert(`상속 프로퍼티: ${prop}`); // 상속 프로퍼티: eats
}
}
ここで興味深いのは、animal
がオブジェクト文字で宣言されているため、Object.prototype
を継承することです.
だからこそ、rabbit
を持つことができますrabbit.hasOwnProperty(key)
MDNドキュメントでは、Object.prototype.someMethod()
が継承されているため、Object.prototype
と同じフォーマットがリストされています.
でもおかしくないですか?hasOwnProperty
メソッドはfor...in
でリストできません.理由は何ですか.hasOwnProperty)
この方法は、Property flags and descriptorsのenumerable
がfalse
であるためである.
3.コンストラクション関数のプロトタイプ
エンティティ・オブジェクトが上に作成され、Object.prototype
が継承される場合、new F()
のようなコンストラクション関数によって作成されるオブジェクトのプロトタイプは何ですか?
重要なことは、コンストラクション関数(F
)のプロトタイプを表すF.prototype
において、prototype
はF
で定義された汎用プロトタイプである.F.prototype
中prototype
は前に学んだ[[Prototype]]
と似ているように聞こえますが、名前が同じだけで、実際には違います.let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("흰 토끼"); // rabbit.__proto__ == animal
alert(rabbit.eats); // true
console.dir(rabbit);
console.dir(Rabbit);
console.dir()
から、図に示すように、コンストラクション関数とコンストラクション関数によって生成されたインスタンスの構造の違いがわかります.
関数のprototype
は、特に割り当てられていなくても、実際にはすべての関数が持つpropertyである.
defaultはconstructor
,constructor
関数そのものを指す
特別な操作が行われていない場合は、new Rabbit
を実行して作成したすべてのウサギオブジェクトがconstructor
propertyを使用できます.この場合、[[Prototype]]
が通過します.function Rabbit() {}
// 디폴트 prototype:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // {constructor: Rabbit}을 상속받음
alert(rabbit.constructor == Rabbit); // true ([[Prototype]]을 거쳐 접근함)
constructor
最初のように新しいオブジェクトを割り当てるよりも、prototype
に必要なプログラムを追加および削除します.function Rabbit() {}
// Rabbit.prototype 전체를 덮어쓰지 말고
// 원하는 프로퍼티가 있으면 그냥 추가합니다.
Rabbit.prototype.jumps = true
// 이렇게 하면 디폴트 프로퍼티 Rabbit.prototype.constructor가 유지됩니다.
誤ってconstructor
を削除すると、手動で再生成できます.これにより、最初のconstructor
の特徴が保証されます.Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
(作成中)
*References
// animal엔 다양한 메서드가 있습니다.
let animal = {
walk() {
if (!this.isSleeping) {
alert(`동물이 걸어갑니다.`);
}
},
sleep() {
this.isSleeping = true;
}
};
let rabbit = {
name: "하얀 토끼",
__proto__: animal
};
// rabbit에 새로운 프로퍼티 isSleeping을 추가하고 그 값을 true로 변경합니다.
rabbit.sleep();
alert(rabbit.isSleeping); // true
alert(animal.isSleeping); // undefined (프로토타입에는 isSleeping이라는 프로퍼티가 없습니다.)
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
// Object.keys는 객체 자신의 키만 반환합니다.
alert(Object.keys(rabbit)); // jumps
// for..in은 객체 자신의 키와 상속 프로퍼티의 키 모두를 순회합니다.
for(let prop in rabbit) alert(prop); // jumps, eats
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
for(let prop in rabbit) {
let isOwn = rabbit.hasOwnProperty(prop);
if (isOwn) {
alert(`객체 자신의 프로퍼티: ${prop}`); // 객체 자신의 프로퍼티: jumps
} else {
alert(`상속 프로퍼티: ${prop}`); // 상속 프로퍼티: eats
}
}
エンティティ・オブジェクトが上に作成され、
Object.prototype
が継承される場合、new F()
のようなコンストラクション関数によって作成されるオブジェクトのプロトタイプは何ですか?重要なことは、コンストラクション関数(
F
)のプロトタイプを表すF.prototype
において、prototype
はF
で定義された汎用プロトタイプである.F.prototype
中prototype
は前に学んだ[[Prototype]]
と似ているように聞こえますが、名前が同じだけで、実際には違います.let animal = {
eats: true
};
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = animal;
let rabbit = new Rabbit("흰 토끼"); // rabbit.__proto__ == animal
alert(rabbit.eats); // true
console.dir(rabbit);
console.dir(Rabbit);
console.dir()
から、図に示すように、コンストラクション関数とコンストラクション関数によって生成されたインスタンスの構造の違いがわかります.関数の
prototype
は、特に割り当てられていなくても、実際にはすべての関数が持つpropertyである.defaultは
constructor
,constructor
関数そのものを指す特別な操作が行われていない場合は、
new Rabbit
を実行して作成したすべてのウサギオブジェクトがconstructor
propertyを使用できます.この場合、[[Prototype]]
が通過します.function Rabbit() {}
// 디폴트 prototype:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // {constructor: Rabbit}을 상속받음
alert(rabbit.constructor == Rabbit); // true ([[Prototype]]을 거쳐 접근함)
constructor
最初のように新しいオブジェクトを割り当てるよりも、prototype
に必要なプログラムを追加および削除します.function Rabbit() {}
// Rabbit.prototype 전체를 덮어쓰지 말고
// 원하는 프로퍼티가 있으면 그냥 추가합니다.
Rabbit.prototype.jumps = true
// 이렇게 하면 디폴트 프로퍼티 Rabbit.prototype.constructor가 유지됩니다.
誤ってconstructor
を削除すると、手動で再生成できます.これにより、最初のconstructor
の特徴が保証されます.Rabbit.prototype = {
jumps: true,
constructor: Rabbit
};
(作成中) *References
Reference
この問題について(プロトタイプとプロトタイプの継承), 我々は、より多くの情報をここで見つけました https://velog.io/@ayaan92/프로토타입과-프로토타입-상속テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol