私たちが作成するすべての関数にはプロトタイプ属性があります。これは、特定の型のすべてのインスタンスで共有できるプロパティとメソッドを含めることを目的としたオブジェクトです。論理的には次のように理解できます。プロトタイプは、コンストラクターを使用して作成されたオブジェクトのプロトタイプ オブジェクトです。プロトタイプを使用する利点は、すべてのオブジェクト インスタンスがそれに含まれるプロパティとメソッドを共有できることです。つまり、コンストラクターでオブジェクト情報を定義する必要はありませんが、この情報をプロトタイプに直接追加します
プロトタイプ メソッドは、オブジェクトのプロトタイプ属性を利用します。新しいオブジェクトの作成に使用されるメソッドとみなされます。ここでは、まず空のコンストラクターを使用して関数名を設定します。次に、すべてのプロパティとメソッドがプロトタイプ属性に直接割り当てられます。前の例を書き直したコードは次のとおりです。
function Car() { }; //将所有的属性的方法都赋予prototype属性 Car.prototype.color = "blue"; Car.prototype.doors = 4; Car.prototype.mpg = 25; Car.prototype.showColor = function() { return this.color; }; var Car1 = new Car(); var Car2 = new Car(); document.write(Car1.showColor()+" ");//输出:blue document.write(Car2.showColor());//输出:blue
このコードでは、最初にコードなしでコンストラクター Car() を定義します。次の数行のコードでは、Car のプロトタイプ プロパティにプロパティを追加することで、Car オブジェクトのプロパティを定義します。 new Car() が呼び出されると、プロトタイプのすべてのプロパティが作成されるオブジェクトに即座に割り当てられます。これは、すべての Car インスタンスが showColor() 関数へのポインターを格納することを意味します。意味的に言えば、すべてのプロパティが 1 つのオブジェクトに属しているように見えるため、以前のファクトリ メソッドとコンストラクター メソッドの問題が解決されます
さらに、このメソッドを使用すると、instanceof 演算子も使用できます。型を確認してください指定された変数が指すオブジェクトの
document.write(Car1 instanceof Car); //输出:tru
プロトタイプのアプローチは良い解決策のように思えます。残念ながら、それほど満足のいくものではありません。まず、このコンストラクターにはパラメーターがありません。プロトタイプ メソッドを使用すると、Car1 と Car2 の color 属性が「blue」に等しく、doors 属性が 4 に等しく、mpg 属性が25.つまり、オブジェクトの作成後にプロパティのデフォルト値を変更する必要があり、面倒ですが、それで終わりではありません。本当の問題は、プロパティが関数ではなくオブジェクトを指す場合に発生します。機能の共有は問題を引き起こしませんが、オブジェクトが複数のインスタンス間で共有されることはほとんどありません。次の例を考えてください:
function Car() { };//定义一个空构造函数,且不能传递参数 Car.prototype.color = "blue"; Car.prototype.doors = 4; Car.prototype.mpg = 25; Car.prototype.drivers = new Array("Mike","John"); Car.prototype.showColor = function() { return this.color; }; var Car1 = new Car(); var Car2 = new Car(); Car1.drivers.push("Bill"); document.write(Car1.drivers+" ");//输出:Mike,John,Bill document.write(Car2.drivers);//输出 :Mike,John,Bill
上記のコードでは、属性ドライバーは、「Mike」と「John」という 2 つの名前を含む Array オブジェクトへのポインターです。ドライバーは参照値であるため、Car の両方のインスタンスは同じ配列を指します。これは、値「Bill」を Car1.drivers に追加することを意味し、これは Car2.drivers にも表示されます。これらのポインタのいずれかを出力すると、文字列「Mike,John,Bill」が表示されます。オブジェクトを作成する際には非常に多くの問題があるため、オブジェクトを作成する合理的な方法はあるのだろうかと疑問に思われるはずです。答えは「はい」です。コンストラクターとプロトタイプのメソッドを組み合わせて使用する必要があります
コンストラクターとプロトタイプの混合メソッド (
< を使用することをお勧めします) 🎜>
function Car(Color,Doors,Mpg) { this.color = Color; this.doors = Doors; this.mpg = Mpg; this.drivers = new Array("Mike","John"); }; Car.prototype.showColor = function() { return this.color; }; var Car1 = new Car("red",4,23); var Car2 = new Car("blue",3,25); Car1.drivers.push("Bill"); document.write(Car1.drivers+" ");//输出:Mike,John,Bill documnet.write(Car2.drivers);//输出:Mike,John
<🎜。 >
Java很好地打包了Car类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,它定义了一个对象的信息。批评混合的构造函数/原型方式的人认为,在构造函数内部找属性,在其外部找方法的做法不合逻辑。因此,他们设计了动态原型方法,以提供更友好的编码风格。
动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的Car:
function Car(Color,Doors,Mpg) { this.color = Color; this.doors = Doors; this.mpg = Mpg; this.drivers = new Array("Mike","John"); //如果Car对象中的_initialized为undefined,表明还没有为Car的原型添加方法 if (typeof Car._initialized == "undefined") { Car.prototype.showColor = function() { return this.color; }; Car._initialized = true; //设置为true,不必再为prototype添加方法 } } var Car1 = new Car("red",4,23);//生成一个Car对象 var Car2 = new Car("blue",3,25); Car1.drivers.push("Bill");//向Car1对象实例的drivers属性添加一个元素 document.write(Car1.drivers+" ");//输出:Mike,John,Bill document.write(Car2.drivers);//输出:Mike,John
直到检查typeof Car._initialize是否等于"undefined"之前,这个构造函数都未发生变化。这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把 Car._initialized设置为true。如果这个值定义了(它的值为 true时,typeof 的值为Boolean),那么就不再创建该方法。简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,传统的 OOP开发者会高兴地发现,这段代码看起来更像其他语言中的类定义了。
我们应该采用哪种方式呢?
如前所述,目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方式也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。总之JS是基于面向对象的一门客户端脚本语言,我们在学习它的面向对象技术的时候要的留意JS与其他严谨性高的程序语言的不同。也要正确使用JS创建对象的合理的方式,推荐使用构造函数与原型方式的混合方式创建对象实例。这样可以避免许多不必要的麻烦。
以上就是JavaScript基于面向对象之创建对象的全部内容,希望对大家的学习有所帮助。
【相关教程推荐】
1. JavaScript视频教程
2. JavaScript在线手册
3. bootstrap教程