オブジェクト指向プログラミング
オブジェクトとは?物とは物理的な物体を抽象化したものです。
オブジェクト指向プログラミングとは、要求をオブジェクトに抽象化し、このオブジェクトを分析し、このオブジェクトにプロパティやメソッドを追加して、物事の関係をモデル化するプロセスです。このオブジェクトは一般的にクラスと呼ばれます。
クラスとインスタンス
const arr = [1,2]
arrはArrayクラスのインスタンスです。
しかし開発においては、JavaScriptの組み込みクラスだけでは十分ではありません。
const Animal = function(){
this.age = 0;
}
Animalは、通常の機能と区別するために、クラス名の最初の文字を大文字にして作成された動物クラスです。このクラスには thisによって年齢属性が定義されています。
コンストラクタと通常の関数実行の違いは何ですか?
const a = new Animal()
console.log(a,window.age) // Animal {age: 0} undefined
const b = Animal()
console.log(b,window.age) // undefined 0
コンストラクタ実行: new Animal()
- まず、デフォルトでオブジェクトが作成されます。
- コンテキストのthisがこのオブジェクトを指すようにします。
- インスタンスオブジェクトを返します。
- returnの値が基本型の場合でも、インスタンスが返されます。
- returnの値が参照型の場合、参照型の値が返されます。
通常の関数実行:Animal()
- thisウィンドウを指します
- returnがない場合はundefinedを返し、returnがある場合はreturnの値を返します。
プロトタイプとプロトタイプチェーン
上記のクラスとインスタンスを作成した後、同じ効果を持つ特定のメソッドを複数のインスタンス・オブジェクトに同時に追加したい場合はどうすればよいでしょうか?
例えば、Animalの2つのインスタンスオブジェクト、dogとpigにsayメソッドを追加する場合、プロトタイプがない場合はこのように書くことができます:
const dog = new Animal()
const pig = new Animal()
dog.say=function(){
console.log("say hello")
}
pig.say=function(){
console.log("say hello")
}
つのsayメソッドは同じ名前で同じ効果をもたらしますが、それぞれヒープメモリの塊を占有します。オブジェクトの多くのインスタンスにsayメソッドを追加することを想像してみてください。メモリが爆発しないでしょうか?
ご心配なく、jsにはそのためのプロトタイプ・メソッドが用意されています:
Animal.prototype.say=function(){
console.log("say hello")
}
プロトタイプは、パブリック・プロパティとメソッドを保持し、インスタンス・オブジェクトのコンストラクタに配置するオブジェクトとして機能します。
console.log(Animal.prototype)
クラスのプロトタイプに共通するプロパティやメソッドは、インスタンスオブジェクトの __proto___ からアクセスできます:
Animal.prototype===dog.__proto__
console.log(dog)
インスタンス・オブジェクトにAnimalクラスを指すコンストラクタ属性があることがわかります。
dog.__proto__.constructor===Animal
Animal.prototype.constructor===Animal
要約すると
- どの関数にもプロトタイプという属性が組み込まれており、その値は公開されているプロパティとメソッドを保持するオブジェクトです。つまり、プロトタイプは、現在のクラスに属するインスタンスに対してパブリックプロパティとメソッドが提供される場所です。
- すべてのオブジェクトには __proto___ 属性があり、その値は現在のインスタンスが属するクラスのプロトタイプです。
- 各オブジェクトには、クラス自身を指すコンストラクタ属性があります。
- プロトタイプ・チェイニング・メカニズム:現在のインスタンス・オブジェクトのプロパティを呼び出すには、まずそのプロパティが自身のプライベート・プロパティに存在するかどうかを確認し、存在する場合は自身のプライベート・プロパティを呼び出します。オブジェクト.プロトタイプ
組み込みクラスのプロトタイプに対するメソッドの拡張
プロトタイプのプロトタイプの上記の理解は、実際にはオブジェクトであり、オブジェクトは、いくつかの組み込みプロパティとメソッドを持っている、それはプロトタイプにいくつかの拡張メソッドを追加しないのですか?答えはイエスです!
一例です:
配列の重複排除は開発でよく使われます。Arrayプロトタイプを拡張して重複排除メソッドを持たせることができます:
Array.prototype.myRemoveRepeat = function removeRepeat() {
// thisメソッドを呼び出したインスタンスオブジェクトを指す
var obj = {};
for (var i = 0; i < this.length; i++) {
var item = this[i];
if (typeof obj[item] !== 'undefined') {
this[i] = this[this.length - 1];
this.length--;
i--;
continue;
}
obj[item] = item;
}
obj = null;
return this // 連鎖書き込みの実装では、戻り値の配列は、メソッドの配列クラスを呼び出すことができる
};
var arr = [1,3,5,2,1,3];
arr.myRemoveRepeat()
拡張メソッドの名前の前に myxxx のような接頭辞をつけて、独自の拡張メソッドが組み込みメソッドに取って代わられるのを防ぐのがよいでしょう。
注: 組み込みクラス・プロトタイプのプロパティは列挙できませんが、組み込みクラス・プロトタイプで拡張されたメソッドは列挙できます。
オブジェクトのプロパティとメソッドは列挙されます。for inループで走査できるものは列挙可能で、走査できないものは列挙できません。
let obj = {
name: "lp",
age: 12
}
for (let key in obj){
console.log(key) // name age Objectプロトタイプは列挙可能だが、メソッドは列挙できない。
}
// 組み込みクラスのプロトタイプにメソッドを追加する
Object.prototype.a = function a(){};
for (let key in obj){
console.log(key) // name age a aまた、列挙可能になる
}
そのため、一般的にfor inでオブジェクトを走査する場合、hasOwnPropertyを使って自分の私有財産かどうかを検出する必要があります。
let obj = {
name: "lp",
age: 12
}
Object.prototype.a = function a(){};
for (let key in obj){
if(obj.hasOwnProperty(key)){
console.log(key) // name age この時点でaはフィルタリングされる
}
}
NEWの時はどうでしたか?
1.インスタンスオブジェクトの作成
2.インスタンスオブジェクトの__proto__がコンストラクタのプロトタイプを指すようにします。
2. thisがインスタンスオブジェクトを指す間、通常の関数としてクラスを実行します。
3は、関数の実行を見てみましょう返り値があるかどうか、存在しないか、または基本的なデータ型の戻り値は、デフォルトの戻り値のインスタンスオブジェクトは、戻り値が参照型の値に戻るには、参照型である場合
新規作成中に何が起こるかを理解するために、モックを実装してみましょう:
function _new(Func, ...args) {
// オブジェクトのインスタンスを作成する
let obj = {};
// のインスタンス・オブジェクトを返そう。__proto__コンストラクタを指すプロトタイプ
obj.__proto__ = Func.prototype;
// 通常の関数としてクラスを実行し、コンストラクタの thisをインスタンス・オブジェクトに向ける。
let result = Func.call(obj,...args);
// resultが参照型であれば、現在の結果を返し、そうでなければインスタンスオブジェクトを返す
return typeof result === 'object' || typeof result === 'function' ? result : obj
}
実装は完了しています:
const Animal = function(){
this.age = 0;
}
let dog = _new(Animal)
console.log(dog.age)





