この記事では主に、オブジェクト指向とJSについて話をする __proto__
、ptototype
とconstrucator
そう一緒に話をし、これらの概念が関連しています、。
私たちは、この最初の話をする前に、私はクラス(クラス)を使用することができますジェネリック型を定義したい場合は、知っておくべきオブジェクト指向の友人を理解するために、そのクラスです。たとえば、Javaで、私たちはクラスを定義できます。
public class Puppy{
int puppyAge; public Puppy(age){ puppyAge = age; } public void say() { System.out.println("汪汪汪"); } }
我々はこのコンストラクタは一つの引数を取り、犬の年齢に加えて、提供されてもよい)プロパティはpuppyAge、犬つまり年齢、およびコンストラクタパピー(ある持つクラスを定義するコード子犬話機能と言います。私たちは、この例では、親クラスのメソッドを持っていながら、2歳の子犬の例は、直接書き込みである必要がある場合には、一般的なクラスです。
Puppy myPuppy = new Puppy( 2 );
myPuppy.say(); // 汪汪汪
しかし、サポート、オブジェクト指向のJSがああなしclassキーワード(JS JSは、主に、ヘルプの人々に、ES6前にclassキーワードを参照していなかった概念を理解すると言う)、JS早く、リードしてより多くの曲がりくねった道を、使用しています私たちは、実際には、我々は一般的なオブジェクト指向の類推で、このように、それは非常にクリアされます、場所を混乱させる。私たちは、両方の曲がりくねった道を解決するものによって、対処する必要がJSへのサポート、オブジェクト指向の問題を見てみましょう。
代わりに、関数のクラスなし、
ファーストクラスのキーワードでもJSは、どのようにそれを行うにはしませんでしたか?代わりに、機能を使用しての、JSは、ほとんどの機能の欠如、機能の共通機能を実行するだけでなく、ときに、クラスの使用です。たとえば、私たちはどのようにそれを書くために子犬のクラスを構築するためにJSを使うのか?ライン上で直接関数を書きます:
function Puppy() {}
この関数は、新しいキーワードを直接インスタンスを作成することができます。
const myPuppy = new Puppy();
我々はまた、子犬の例を持っているが、我々はコンストラクタを持っていない、あなたは犬のああの年齢を設定することはできません。
コンストラクタ関数自体
それ自体でクラスとしての機能の関数であり、彼はデフォルトコンストラクタです。我々は、彼がラインにパラメータを受け取る限り、年齢の子犬の機能の一例を設定します。
function Puppy(age) {
this.puppyAge = age; } // 实例化时可以传年龄参数了 const myPuppy = new Puppy(2);
注上記のコードは、そのthis
クラスのインスタンスとして使用されるこの関数は常にオブジェクト、すなわちmyPuppyを指します。このような設計の目的は、ユーザがインスタンスのコンストラクタによってオブジェクトのプロパティを設定できるようにすることで、コンソールを見るために、このタイムアウトはmyPuppy.puppyAge
2です。
console.log(myPuppy.puppyAge); // 输出是 2
プロトタイプと方法の例
私たちは、クラスとコンストラクタを実現しますが、クラスメソッド上記の?子犬のJavaのバージョンも「樹皮王」は、それを行う方法のJSバージョン、それを呼ばれることができますか?JS溶液の分析方法に添加されるprototype
上記ローディング方法は、オブジェクトのインスタンスを与えるためにインスタンス化されたプロパティ。私たちは、あなたがする必要がある、myPuppyが話すことができますしたいPuppy.prototype
話をする方法を追加します。
Puppy.prototype.say = function() {
console.log("汪汪汪"); }
新しいキーワードは、クラス生成された使用例prototype
属性およびメソッドを、私たちはPuppy.prototype
言うメソッドを追加することで、myPuppyは、私が試してみてどのような、話すことができます。
myPuppy.say(); // 汪汪汪
見つけるために使用方法の例__proto__
myPuppyはあなたが呼び出すことができますどのようにsay
それの方法を、私たちは、プリントアウトして彼に見て、ああから来ているこのオブジェクトを、言いませんでしたか?
これは__proto__
、プロパティがオンになっていないオブジェクトにアクセスする際、遊び、たとえばmyPuppy.say
、するオブジェクトを__proto__
見つけます。__proto__
プロトタイプは、親クラスの値に等しい myPuppy.__proto__
指しますPuppy.prototype
。
あなたはプロパティが訪問した場合はPuppy.prototype
存在しない、それが行き続けるPuppy.prototype.__proto__
見つけることで、実際には、この時間は見つけるためにObject.prototype
、そしてObject.prototype
その後、さらに上のことはしなかった見つけるために、それがnullで、これは実際にプロトタイプチェーンです。
constructor
私たちは、クラスのコンストラクタを指し、一般的に話していますprototype.constructor
。prototype.constructor
現在のクラスのコンストラクタを示すためのプロトタイプ上の予約属性、関数自体にクラス属性ポイントが、あります。
それは以来prototype.constructor
、我々はコンストラクタによって変更することができないことを、コンストラクタへのポインタであるそれを行いますか?のは知ってみましょう。のは、この機能を変更して、結果の新しいインスタンスの外観を作成してみましょう:
function Puppy(age) {
this.puppyAge = age; } Puppy.prototype.constructor = function myConstructor(age) { this.puppyAge2 = age + 1; } const myPuppy2 = new Puppy(2); console.log(myPuppy2.puppyAge); // 输出是2
例が示すように、我々はモディファイprototype.constructor
のみだけでこの指標を変更し、実際のコンストラクタを変更しません。
何人かの友人は、私が印刷言うmyPuppy2.constructor
値ああ、持っても、constructor
オブジェクト自体のプロパティがそれではないですか?まあ、それはまさに、あなたが見つけmyPuppy2を印刷するとき、それ自体がこの性質を持っており、プロトタイプチェーンを探して行ってきましたしていないため、この値は、彼が見つけた理由をプリントアウトすることができますprototype.constructor
。私たちはすることができますhasOwnProperty
知って見て:
我々は、それはそれを明確にし、実際に持っている上にprototype
、__proto__
、constructor
数人の関係は、以下がより直感的に見て絵を描きます:
staticメソッド
私たちは、このような直接的なJavaが追加されるなどの静的メソッド、オブジェクト指向の概念の多くがいることを知っているstatic
キーワードは、静的メソッドのためのメソッドを定義することができるようになりますが。JSは、ライン属性クラスの関数として直接、静的メソッドは単純であることを定義します。
Puppy.statciFunc = function() { // statciFunc就是一个静态方法
conlose.log('我是静态方法,this拿不到实例对象'); } Puppy.statciFunc(); // 直接通过类名调用
静的およびインスタンスメソッドは、主な違いは、インスタンスにアクセスすることができ、例えば動作することができる、一般的に操作を行うには、インスタンス何のために使用される静的メソッドインスタンスメソッドです。jQueryのは、これらの方法の両方は、アプリケーションのjQueryの多数を持っている$(selector)
実際によるオブジェクトのインスタンスを取得$(selector)
操作のメソッドがインスタンスメソッドです。例えば$(selector).append()
、それは新たな要素を追加し、この例のDOMに行くだろう、彼はDOMインスタンス操作は、どのように知っている必要があるappend
インスタンスメソッドとして、彼は、DOMインスタンスは、この介して動作することができます。この例の内部を指します。それを行うには、静的な方法として適しているのはどのような方法ですか?例えば$.ajax
ここで、ajax
DOMインスタンスと、それは問題で、これはこれを必要としないしない、それが直接の静的メソッドとして$に取り付けることができます。
継承
面向对象怎么能没有继承呢,根据前面所讲的知识,我们其实已经能够自己写一个继承了。所谓继承不就是子类能够继承父类的属性和方法吗?换句话说就是子类能够找到父类的prototype
,最简单的方法就是子类原型的__proto__
指向父类原型就行了。
function Parent() {}
function Child() {} Child.prototype.__proto__ = Parent.prototype; const obj = new Child(); console.log(obj instanceof Child ); // true console.log(obj instanceof Parent ); // true
上述继承方法只是让Child访问到了Parent原型链,但是没有执行Parent的构造函数:
function Parent() {
this.parentAge = 50; } function Child() {} Child.prototype.__proto__ = Parent.prototype; const obj = new Child(); console.log(obj.parentAge); // undefined
为了解决这个问题,我们不能单纯的修改Child.prototype.__proto__
指向,还需要用new执行下Parent的构造函数:
function Parent() {
this.parentAge = 50; } function Child() {} Child.prototype.__proto__ = new Parent(); const obj = new Child(); console.log(obj.parentAge); // 50
上述方法会多一个__proto__
层级,可以换成修改Child.prototype
的指向来解决,注意将Child.prototype.constructor
重置回来:
function Parent() {
this.parentAge = 50; } function Child() {} Child.prototype = new Parent(); Child.prototype.constructor = Child; // 注意重置constructor const obj = new Child(); console.log(obj.parentAge); // 50
当然还有很多其他的继承方式,他们的原理都差不多,只是实现方式不一样,核心都是让子类拥有父类的方法和属性,感兴趣的朋友可以自行查阅。
自己实现一个new
结合上面讲的,我们知道new其实就是生成了一个对象,这个对象能够访问类的原型,知道了原理,我们就可以自己实现一个new了。
function myNew(func, ...args) {
const obj = {}; // 新建一个空对象 func.call(obj, ...args); // 执行构造函数 obj.__proto__ = func.prototype; // 设置原型链 return obj; } function Puppy(age) { this.puppyAge = age; } Puppy.prototype.say = function() { console.log("汪汪汪"); } const myPuppy3 = myNew(Puppy, 2); console.log(myPuppy3.puppyAge); // 2 console.log(myPuppy3.say()); // 汪汪汪
自己实现一个instanceof
知道了原理,其实我们也知道了instanceof是干啥的。instanceof不就是检查一个对象是不是某个类的实例吗?换句话说就是检查一个对象的的原型链上有没有这个类的prototype
,知道了这个我们就可以自己实现一个了:
function myInstanceof(targetObj, targetClass) {
// 参数检查 if(!targetObj || !targetClass || !targetObj.__proto__ || !targetClass.prototype){ return false; } let current = targetObj; while(current) { // 一直往原型链上面找 if(current.__proto__ === targetClass.prototype) { return true; // 找到了返回true } current = current.__proto__; } return false; // 没找到返回false } // 用我们前面的继承实验下 function Parent() {} function Child() {} Child.prototype.__proto__ = Parent.prototype; const obj = new Child(); console.log(myInstanceof(obj, Child) ); // true console.log(myInstanceof(obj, Parent) ); // true console.log(myInstanceof({}, Parent) ); // false
总结
最后来个总结,其实前面小节的标题就是核心了,我们再来总结下:
- JS中的函数可以作为函数使用,也可以作为类使用
- 作为类使用的函数实例化时需要使用new
- 为了让函数具有类的功能,函数都具有
prototype
属性。 - 为了让实例化出来的对象能够访问到
prototype
上的属性和方法,实例对象的__proto__
指向了类的prototype
。所以prototype
是函数的属性,不是对象的。对象拥有的是__proto__
,是用来查找prototype
的。 prototype.constructor
これは、クラス自体の関数であり、コンストラクタ、を指します。コンストラクタを変更しないポインタを変更します。- オブジェクトそのものではありません
constructor
あなたはプロトタイプチェーンであるへのアクセスを持って、プロパティprototype.constructor
。 - 自身がオブジェクトである関数は、また
__proto__
、彼は、組み込みオブジェクトのJSを指しFunction
プロトタイプFunction.prototype
。あなたが呼び出すことができるのでfunc.call
、func.apply
これらの方法は、あなたが実際に呼び出すFunction.prototype.call
とFunction.prototype.apply
。 prototype
自身のオブジェクトであるので、彼は持っている__proto__
、彼の親を指しますprototype
。__proto__
そして、prototype
この点は、JSのプロトタイプチェーンのチェーンを構成しています。プロトタイプチェーンの最後の点であるObject
プロトタイプ。Object
上記プロトタイプチェーンがヌル、すなわち、ですObject.prototype.__proto__ === null
。- また、ご注意
Function.__proto__ === Function.prototype
JSは、すべての機能をプロトタイプのでありFunction.prototype
、すべての機能があることをどの手段Function
の例。Function
機能自体は----として使用することができますFunction()
ので、彼にもある、Function
インスタンス。そこに類似しているObject
、Array
というように、彼らはまた、関数として使用することができますObject()
、Array()
。だから、自分自身の原型であるFunction.prototype
、それはありますObject.__proto__ === Function.prototype
。言い換えれば、これらは、新しいビルトインされる可能性のあるオブジェクトだけで私たちの子犬同じカテゴリのように、実際には親切です。
そして、全体像を見て: