Jsモデルを深く理解する


一、モデルとは何ですか?
jsにおいて、対象を作成する方式は工場モードと構造関数モードなどがあります。コンストラクタモードの最大の問題は、コンストラクタにおける各方法は、インスタンスオブジェクトの中で再作成する必要があり、多重化できないので、この問題を解決するためには、プロトタイプパターンを使用してオブジェクトを作成する必要があるということである。
プロトタイプモードは、すべてのインスタンスを共有する方法と属性をプロトタイプという属性の中に置いて、関数を作成する時にプロトタイプ属性があります。この属性は、オブジェクトを指すポインタであり、構成関数を呼び出して作成されたオブジェクトインスタンスのプロトタイプオブジェクトです。

//     
function Person() {};
//     prototype
Person.prototype.name = '  ';
Person.prototype.sayName = function() {
console.log(this.name);
};
let person1 = new Person();
person1.sayName(); //  
let person2 = new Person();
person2.sayName(); //   
console.log(person1.sayName == person2.sayName); //true
1.原型の対象を理解する
いつでも、新しい関数を作成すると、関数のプロトタイプ属性を作成します。この属性指向関数のプロトタイプオブジェクトは、デフォルトではすべてのプロトタイプオブジェクトが自動的に一つのconstrutor属性を獲得します。これはポインタで、プロトタイプの属性がある関数を指します。カスタムコンストラクタを作成した後、元のオブジェクトはデフォルトではconstructor属性のみを取得します。他の方法はObjectから引き継ぎます。
構造関数を呼び出して新しいインスタンスオブジェクトを作成すると、その例の内部には、構造関数のプロトタイプを指すポインタが含まれます。この接続はインスタンスとコンストラクタのプロトタイプオブジェクトの間に存在し,インスタンスとコンストラクタの間に存在しない。
あるオブジェクトの属性をコードが読み込むたびに、名前が与えられた属性を持つ検索を行います。検索はまず、オブジェクトのインスタンス自体から開始します。例で見つけたら属性の値を返します。見つからない場合は、ポインタが指すプロトタイプオブジェクトを検索し続けます。プロトタイプオブジェクトで指定された名前の属性を検索します。プロトタイプオブジェクトでこの属性が見つかったら、その属性の値を返します。
プロトタイプに保存された値にインスタンスでアクセスすることができますが、プロトタイプの値をインスタンスオブジェクトで書き換えることはできません。プロトタイプに付けられた同名の属性をインスタンスに追加すると、プロトタイプの属性は自動的に遮蔽されますが、プロトタイプの属性は変更されず、プロトタイプにアクセスする属性は阻止されます。プロトタイプの属性に再アクセスすることができます。
2.原型とin操作符
ハスOwnProperty()方法は、属性がインスタンスオブジェクトに存在するかどうかを検出し、

//     
function Person() {
this.age = 16;
};
Person.prototype.name = "  ";
let person1 = new Person();
console.log(person1.hasOwnProperty('name')); // false
console.log(person1.hasOwnProperty('age')); // true
inオペレータの使用は、2つのクラスに分けられ、単独で使用し、for-i-nで循環して使用することができ、単独で使用する場合、inオペレータは、オブジェクトを通じて指定された属性にアクセスできるときにtrueに戻り、この属性がインスタンスに存在するか、それともプロトタイプに存在するかに関わらず、trueに戻ります。

//     
function Person() {}
Person.prototype.name = 'zhang';
let person1 = new Person();
console.log('name' in person1); // true
person1.age = 14;
console.log('age' in person1); // true
hasOwnProperty()方法とin操作符を同時に使用して、この属性を確定することができます。

//     
function Person() {}
function hasPrototypeProperty(object, name) {
return !object.hasOwnProperty(name) && (name in object);
}
Person.prototype.name = "  ";
let person = new Person();
console.log(hasPrototypeProperty(person, 'name')); // true
console.log(hasPrototypeProperty(person, 'age')); // false
for-innループを使用すると、オブジェクトを介してアクセスできる、エニュメレート・属性のすべてが返されます。ここでは、インスタンスに存在する属性も含め、プロトタイプに存在する属性も含まれます。

let o = {
name: 'san',
age: 14,
};
for(let key in o) {
console.log(key);
}
オブジェクト上のすべてのエニュメレート・インスタンス属性を取得するには、Object.keys()法を使用して、オブジェクトをパラメータとして受信し、すべてのエニュメレート・属性を含む文字列配列を返します。
すべてのインスタンス属性を取得したい場合。エニュメレーションの有無にかかわらず、Object.getOwn PropertyNames()の方法が使用されます。
3.より簡単な原型文法
不必要な入力と視覚的に優れたパッケージプロトタイプの機能を低減するために、一般的なアプローチは、すべての属性と方法を含むオブジェクトの字面量を用いて、プロトタイプオブジェクト全体を書き換えることである。

//     
function Person() {};
Person.prototype = {
sayHi: function() {
console.log(hi);
},
name: '  ',
};
このようにすると、プロトタイプのオブジェクトのconstructor属性がPersonに向けられなくなります。もしconstructorの値が本当に重要であれば、以下のようにわざわざ適切な値に設定してもいいです。

//     
function Person() {};
Person.prototype = {
constructor: Person,
sayHi: function() {
console.log(hi);
},
name: '  ',
};
ただし、このようにすると対象の[Enumerable]特性がtureに設定され、デフォルトではconstruct属性の場合は列挙できないものがあり、Object.defineProperty()によって解決されます。

//     
function Person() {};
Person.prototype = {
sayHi: function() {
console.log(hi);
},
name: '  ',
};
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false,
value: Person
}
4.原型の動態性
元のオブジェクトに対する変更は、直ちにインスタンスから反映されます。

function Person() {};
var friend = new Person();
Person.prototype.sayHi = function() {
console.log('hi');
};
friend.sayHi(); // hi
しかし、元のオブジェクト全体を書き換えると、状況が違ってきます。コンストラクタを呼び出したときには、インスタンスに最初のプロトタイプを指す「プロトタイプ」のポインタを追加します。プロトタイプを他のオブジェクトに変更すると、コンストラクターと最初のプロトタイプとの間の連絡が切断されます。実例中のポインタはプロトタイプだけを指し、コンストラクタを指すのではない。

//     
function Person() {};
var friend = new Person();
Person.prototype = {
constructor: Person,
sayHi: function() {
console.log(hi);
}
};
friend.sayHi(); // Uncaught TypeError: friend.sayHi is not a function
Personの例を作成し、その原型オブジェクトを書き換えた。しかし、sayHi()を使用している間にエラーが発生しました。この場合、インスタンスが指すプロトタイプのオブジェクトは新しいオブジェクトです。プロトタイプオブジェクトを書き換えて、既存のプロトタイプと既存のオブジェクトインスタンスとの直接的な関連を切断しました。だから新聞を間違えました。
5.原生対象の原型
プロトタイプの重要性は、カスタムタイプの作成だけでなく、すべてのオリジナルの引用タイプまでこのパターンを採用しており、すべてのオリジナル引用タイプ(Object、Aray、String)などは、その構造関数のプロトタイプに方法を定義しています。カスタムオブジェクトの原型を変更するように、元のオブジェクトの原型を変更することができます。
二、モデルの欠点
参照タイプの値を含む属性については、すべてのインスタンスがデフォルトで同じ属性値を取得します。

//     
function Person() {};
//     prototype
Person.prototype = {
constructor: Person,
friends: ['  ', '  '],
}
let person1 = new Person();
let person2 = new Person();
person1.friends.push('  ');
console.log(person1.friends); // ["  ", "  ", "  "]
console.log(person2.friends); // ["  ", "  ", "  "]
friendsはPersonのプロトタイプのオブジェクトの中に存在するため、person 1対friendsの修正もperson 2を通じて反応しますが、対象となるのは普通は自分の全部の属性が必要です。そのため、プロトタイプを単独で使う人は少ないです。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。