JavaScript でオブジェクト (クラス) を作成する 8 つの方法を Yiyi が紹介します。気に入っていただければ幸いです。
1. Object コンストラクターを使用してオブジェクトを作成します。
次のコードは、person オブジェクトを作成し、2 つの方法で Name 属性値を出力します。
var person = new Object(); person.name="kevin"; person.age=31; alert(person.name); alert(person["name"])
上記の書き方の別の形式は、オブジェクト リテラルを使用してオブジェクトを作成することです。person[“5”] に驚かないでください。これはここでは合法です。それ以外の場合はこれを使用します。括弧で囲まれた方法では、person["my age"] のようにフィールド間にスペースを入れることができます。
var person = { name:"Kevin", age:31, 5:"Test" }; alert(person.name); alert(person["5"]);
オブジェクト コンストラクターまたはオブジェクト リテラルですが単一のオブジェクトを作成するために使用できますが、これらのメソッドには明らかな欠点があります。同じインターフェイスを使用して多数のオブジェクトを作成すると、大量の重複コードが生成されます。この問題を解決するために、人々は工場のパターンのバリエーションを使い始めました。
2. ファクトリ パターン
ファクトリ パターンは、ソフトウェア エンジニアリングの分野でよく知られている設計パターンです。 ECMAScript クラスを作成できないため、開発者は、次の例に示すように、特定のインターフェイスを使用してオブジェクト作成の詳細をカプセル化する関数を発明しました。
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson("Nicholas", 29, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor");
ファクトリ パターンは、複数の同様のオブジェクトを作成する問題を解決しますが、オブジェクト認識 (つまり、オブジェクトの種類を知る方法) の問題は解決しません。 。 JavaScript
の発展により、別の新しいパターンが登場しました。
3. コンストラクター パターン
Object や Array などのコンストラクターは、実行時に実行環境に自動的に表示されます。さらに、カスタム コンストラクターを作成して、カスタム オブジェクト タイプのプロパティとメソッドを定義できます。たとえば、前の例はコンストラクター パターンを使用して次のように書き換えることができます。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
この例では、createperson() 関数が person() 関数に置き換えられます。 createPerson() と同じ部分に加えて、Person() のコードには次の違いがあることに気付きました。
オブジェクトは明示的に作成されません。 🎜>
の 4 つのステップが実行されます。 (1) 新しいオブジェクトを作成します。
(2) スコープを構築します。関数の値が新しいオブジェクトに割り当てられます (つまり、これは新しいオブジェクトを指します);(3) はコンストラクター内のコードを実行します (新しいオブジェクトに属性を追加します)。 。
前の例の最後で、person1 と person2 はそれぞれ person の異なるインスタンスを保持しています。以下に示すように、どちらのオブジェクトにも person を指すコンストラクター属性があります。
alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true
alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true
コンストラクター パターンは使いやすいですが、欠点がないわけではありません。コンストラクターを使用する場合の主な問題は、各インスタンスで各メソッドを再作成する必要があることです。
ECMAScript の関数はオブジェクトであるため、関数が定義されるたびにオブジェクトがインスタンス化されます。このときのコンストラクターも論理的には次のように定義できます。function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = new Function("alert(this.name)"); // 与声明函数在逻辑上是等价的 }
alert(person1.sayName == person2.sayName); //false
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
4. プロトタイプモード
要理解原型对象,可见我的另一篇博客:JavaScript prototype详解
前面例子中每添加一个属性和方法就要敲一遍Person.prototype。为减少不必要的输入,也为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,如下面的例子所示。
function Person(){ } Person.prototype = { name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
在上面的代码中,我们将Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外:constructor 属性不再指向Person 了。前面曾经介绍过,每创建一个函数,就会同时创建它的prototype 对象,这个对象也会自动获得constructor 属性。而我们在这里使用的语法,本质上完全重写了默认的prototype 对象,因此constructor 属性也就变成了新对象的constructor 属性(指向Object 构造函数),不再指向Person 函数。此时,尽管instanceof操作符还能返回正确的结果,但通过constructor 已经无法确定对象的类型了,如下所示。
var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true
在此,用instanceof 操作符测试Object 和Person 仍然返回true,但constructor 属性则等于Object 而不等于Person 了。如果constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。
function Person(){ } Person.prototype = { constructor : Person, name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
需要注意一点就是:实例中的指针仅指向原型,而不指向构造函数。
原型对象的问题:原型模式也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便,但还不是原型的最大问题。原型模式的最大问题是由其共享的本性所导致的。
function Person(){ } Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", friends : ["Shelby", "Court"], sayName : function () { alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court,Van" alert(person1.friends === person2.friends); //true
5、组合使用构造函数模式和原型模式(最常用)
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby", "Court"]; } Person.prototype = { constructor : Person, sayName : function(){ alert(this.name); } } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Count,Van" alert(person2.friends); //"Shelby,Count" alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true
6、动态原型模式
有其他OO 语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常困惑。动态原型模式正是致力于解决这个问题的一个方案,它把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。换句话说,可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。来看一个例子。
function Person(name, age, job){ //属性 this.name = name; this.age = age; this.job = job; //方法 --------------------------------------------- if (typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; } -------------------------------------------- } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName();
7、寄生构造函数模式
通常,在前述的几种模式都不适用的情况下,可以使用寄生(parasitic)构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。下面是一个例子。
function Person(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName(); //"Nicholas"
在这个例子中,Person 函数创建了一个新对象,并以相应的属性和方法初始化该对象,然后又返回了这个对象。除了使用new 操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实是一模一样的。构造函数在不返回值的情况下,默认会返回新对象实例。
8、稳妥构造函数模式
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this 的对象。稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用this 和new),或者在防止数据被其他应用程序(如Mashup程序)改动时使用。稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的实例方法不引用this;二是不使用new 操作符调用构造函数。按照稳妥构造函数的要求,可以将前面的Person 构造函数重写如下。
function Person(name, age, job){ //创建要返回的对象 var o = new Object(); //可以在这里定义私有变量和函数 //添加方法 o.sayName = function(){ alert(name); }; //返回对象 return o; }
JavaScript でオブジェクト (クラス) を作成する上記の 8 つの方法を学習しましたか? 学習に役立つことを願っています。
【おすすめ関連チュートリアル】
1. JavaScript ビデオチュートリアル
2. JavaScript オンラインマニュアル
3.ブートストラップ チュートリアル