OO Javascriptコンストラクターパターン:ネオクラシックとプロトタイプ
-
05-07-2019 - |
質問
その講演で、彼は私にとってかなり驚くべき洞察に満ちた声明を発表しました。たとえば、JavaScriptは地球上で最も重要なプログラミング言語です。または、それは地球上で最も人気のある言語です。そして、それは多くの深刻な方法で壊れていること。
私にとって彼がした最も驚くべき発言は、「新しいことは危険です」でした。彼はもうそれを使用しません。彼は this
も使用していません。
彼は、Javascriptのコンストラクターに興味深いパターンを提示しました。これは、プライベートおよびパブリックメンバー変数を許可し、 new
も this
にも依存しません。次のようになります:
// neo-classical constructor
var container = function(initialParam) {
var instance = {}; // empty object
// private members
var privateField_Value = 0;
var privateField_Name = "default";
var privateMethod_M1 = function (a,b,c) {
// arbitrary
};
// initialParam is optional
if (typeof initialParam !== "undefined") {
privateField_Name= initialParam;
}
// public members
instance.publicMethod = function(a, b, c) {
// because of closures,
// can call private methods or
// access private fields here.
};
instance.setValue = function(v) {
privateField_Value = v;
};
instance.toString = function(){
return "container(v='" + privateField_Value + "', n='" + privateField_Name + "')";
};
return instance;
}
// usage
var a = container("Wallaby");
WScript.echo(a.toString());
a.setValue(42);
WScript.echo(a.toString());
var b = container();
WScript.echo(b.toString());
編集:小文字のクラス名に切り替えるためにコードが更新されました。
このパターンは、 Crockfordの以前の使用モデルから発展しました。
質問:この種のコンストラクタパターンを使用していますか?理解できると思いますか?もっと良いものはありますか?
解決
他のヒント
ほとんどの人が読みにくいと思うので、このパターンは避けます。私は通常、2つのアプローチに従います。
-
何かしか持っていない場合は、匿名オブジェクトを使用します:
var MyObject = { myMethod: function() { // do something } };
-
複数の場合、標準のjavascriptプロトタイプ継承を使用します
var MyClass = function() { }; MyClass.prototype.myMethod = function() { // do something }; var myObject = new MyClass();
(1)は、読み取り、理解、および書き込みがはるかに簡単です。 (2)複数のオブジェクトがある場合、より効率的です。 Crockfordのコードは、コンストラクター内に毎回関数の新しいコピーを作成します。クロージャには、デバッグが難しいという欠点もあります。
真にプライベートな変数は失われますが、プライベートとして想定されるメンバーには慣例として _
をプレフィックスとして付けます。
this
は明らかにJavaScriptで難しい問題ですが、 .call
と .apply
を使用して適切に設定することで回避できます。また、よく var self = this;
を使用して、メンバー関数内で定義された関数内で this
として使用するクロージャー変数を作成します。
MyClass.prototype.myMethod = function() {
var self = this;
// Either
function inner1() {
this.member();
}
inner1.call(this);
// Or
function inner2() {
self.member();
}
inner2();
};
この種のコンストラクタパターンを使用しますか?
いいえ
理解できると思いますか?
はい、非常に簡単です。
より良いものがありますか?
この講演はまだ見ていませんが、すぐに話をする予定です。 それまでは、 new
および this
を使用する危険性はありません。その理由は次のとおりです。
彼の要点を聞いていないので、彼は this
の性質と、特定の状況に応じて変化する傾向があるため、そのようなことから遠ざかることを提案していると推測できますメソッドが実行されます(元のオブジェクトに直接、またはコールバックとして)。教育者として、彼はこれらのキーワードの回避を教えているかもしれません。なぜなら、最初に言語の性質を理解することなくJavaScriptに手を出している、ほとんど知らない開発者の人口統計のためです。言語に精通している経験豊富な開発者にとっては、言語のこの機能を回避する必要があるとは確信していません。この機能を使用すると、驚くほどの柔軟性が得られます( with コード>)。とにかく、私は今それを見ています。
とにかく、自動マジック継承をサポートする何らかのフレームワーク( dojo.declare
など)を使用しない場合、またはフレームワークに依存しないオブジェクトを作成する場合、現在次のアプローチを採用しています。
定義:
var SomeObject = function() {
/* Private access */
var privateMember = "I am a private member";
var privateMethod = bindScope(this, function() {
console.log(privateMember, this.publicMember);
});
/* Public access */
this.publicMember = "I am a public member";
this.publicMethod = function() {
console.log(privateMember, this.publicMember);
};
this.privateMethodWrapper = function() {
privateMethod();
}
};
使用法:
var o = new SomeObject();
o.privateMethodWrapper();
bindScope
は、Dojoの dojo.hitch
またはPrototypeの Function.prototype.bind
に類似したユーティリティ関数です。
彼の本では、機能的継承と呼ばれています(52ページ)。まだ使いません。 Douglasからjavascriptを学べば理解できます。もっと良いアプローチはないと思います。これは次の理由で優れています:
-
プログラマがプライベートメンバーを作成できるようにする
-
プライベートメンバーを保護し、ふりをするプライバシーとは対照的に this を排除します(プライベートメンバーは_で始まります)
-
不要なコードを使用せずに継承をスムーズにします
ただし、いくつかの欠点があります。詳細については、 http://www.bolinfest.com/javascript/inheritanceをご覧ください。 php
この種のコンストラクターパターンを使用しますか?
このパターンを使用したのは、JavaScriptを初めて学習したときにダグラス・クロックフォードの文学に出会ったときです。
理解できると思いますか?
クロージャを理解している限り、この方法は明確です。
より良いものがありますか?
何を達成しようとしているかによって異なります。可能な限り馬鹿な証拠になるライブラリを作成しようとしている場合、私はプライベート変数の使用を完全に理解できます。これにより、ユーザーがオブジェクトの整合性を不注意に乱すことを防ぐことができます。はい、時間のコストはわずかに大きくなる可能性があります(約3倍)が、時間のコストは実際にアプリケーションに影響を与えるまでは議論の余地があります。以前の投稿(テスト)で言及されたテストは、アクセスにかかる時間を考慮していないことに気付きました。オブジェクトの機能。
prototype / constructorメソッドは、通常、構築時間の短縮につながりますが、検索時間を節約できるとは限りません。プロトタイプチェーンを使用して関数を検索する場合と、使用しているオブジェクトに関数を直接接続する場合とでは、追加のコストがかかります。したがって、多くのプロトタイプ関数を呼び出しており、多くのオブジェクトを構築していない場合は、Crockfordのパターンを使用する方が理にかなっています。
私は、多くの読者向けにコードを書いていない場合、プライベート変数を使用するのは好きではありません。私がすべて有能なコーダーである人々のチームと一緒にいる場合、私は一般的に、自分でコードを書き、コメントするなら、彼らが私のコードの使い方を知っていると信じることができます。それから、プライベートメンバー/メソッドを使用しない、クロックフォードのパターンに似たものを使用します。
常に同じ種類のオブジェクトを作成する必要がある場合は、プロトタイプコンストラクターパターンを使用します。これにより、自動委任を通じて >プロトタイプチェーン。
プライベートオブジェクトを保持することもできます。このアプローチを見てください:
var ConstructorName = (function() { //IIFE
'use strict';
function privateMethod (args) {}
function ConstructorName(args) {
// enforces new (prevent 'this' be the global scope)
if (!(this instanceof ConstructorName)) {
return new ConstructorName(args);
}
// constructor body
}
// shared members (automatic delegation)
ConstructorName.prototype.methodName = function(args) {
// use private objects
};
return ConstructorName;
}());
コンストラクター関数を作成する興味深い方法を見つけることができるこの回答を確認することをお勧めします: Javascriptを作成する別の方法オブジェクト
これは、プロトタイプコンストラクターのアプローチを使用できる例です。 JavaScriptでカスタムエラーを作成するにはどうすればよいですか。
ダグラス・クロックフォードの“ Advanced JavaScript”プレゼンテーションビデオ。
主なポイントは、new演算子の使用を避けることです。 オブジェクトコンストラクター関数を呼び出すときにnew演算子の使用を忘れると、コンストラクターに追加されたオブジェクトメンバーはすべてグローバル名前空間になります。 この場合、間違いを知らせる実行時の警告やエラーはないことに注意してください。グローバル名前空間は単純に汚染されます。 そして、これは深刻なセキュリティへの影響があり、バグを診断するのが難しい多くの原因であることが証明されています。
これがこのPowerconstructorパターンの要点です。
プライベート/特権部分はセカンダリです。別の方法でそれをしても大丈夫です。 プロトタイプメンバーは使用されません。
HTH luKa