2

配列に格納されている JavaScript 疑似クラスの名前を特定の名前で設定したいのですが、たとえば、配列ではないバージョンは問題なく動作します。

var Working = new Array();
Working = new Function('arg', 'this.Arg = arg;');
Working.prototype.constructor = Working;
var instw = new Working('test');
document.write(instw.Arg);
document.write('<BR />');
document.write((instw instanceof Working).toString());

出力:

test
true

ただし、この形式は機能しません。

// desired name of pseudoclass
var oname = 'Obj';

var objs = new Array();
objs.push(new Function('arg', 'this.Arg = arg;'));

// set objs[0] name - DOESN'T WORK
objs[0].prototype.constructor = oname;

// create new instance of objs[0] - works
var inst = new objs[0]('test');
document.write(inst.Arg);

document.write('<BR />Redundant: ');
// check inst name - this one doesn't need to work
try { document.write((inst instanceof objs[0]).toString()); } catch (ex) { document.write('false'); }
document.write('<BR />Required: ');
// check inst name - this is the desired use of instanceof
try { document.write((inst instanceof Obj).toString()); } catch (ex) { document.write('false'); }

出力:

test
Redundant: true
Required: false

JSFiddle へのリンク

4

1 に答える 1

2

ここでは、JS の流暢さに関して少しずれていることがいくつかあります (それは問題ありません。4.0 のベース言語機能を離れるとすぐに、私の C# はかなりハックニーになります)。

まず、絶対に避けることをお勧めdocument.writeしますか?
これには技術的な理由があり、ブラウザは最近それらを回避しようと懸命に努力していますが、それでもどこにでも配置するのと同じくらい悪い考えalert()です (反復を含む)。
Windows のシステム メッセージ ポップアップがいかに煩わしいものであるかは、誰もが知っています。

Chrome を使用している場合は、ヒットCTRL+Shift+Jすると便利なコンソールが表示console.log()され、(オブジェクト/配列/関数であっても) データセット/DOM オブジェクトのトラバース可能なノードと、他のタイプの文字列を返すことができます (機能)。最近の JS の最も優れた機能の 1 つは、IDE がブラウザー内にあるという事実です。
ゼロから作成して .js ファイルを保存することは、コンソールから特に簡単ではありませんが、テスト/デバッグはこれほど簡単ではありません。

さて、実際の問題に移ります。

例 #1 で何をしているのか見てみましょう。.prototype.constructorいくつかのエッジケースのブラウザ/エンジンが存在しない限り、の書き換えはまったく不要です。

コンストラクターとして使用される (つまり、 で呼び出される) 関数の内部ではnew、関数は基本的に新しい object を作成し、それを、 setting 、および settingに{}割り当てます。thisthis.__proto__ = arguments.callee.prototypethis.__proto__.constructor = arguments.calleearguments.callee === function

var Working = function () {};
var working = new Working();
console.log(working instanceof Working); // [log:] true

Workingは文字列ではありません: 関数にしています。
実際、JS では、window(ブラウザでは) のプロパティでもあります。

window.Working    === Working;  // true
window["Working"] === Working; // true

最後の 1 つは、例 2 のジレンマを解決するための鍵です。

ただし、#2 を見る前に注意点があり
ます。大量の疑似サブクラス化を行っている場合は、

var Shape = function () {
    this.get_area = function () { };
},

Square = function (w) {
    this.w = w;
    Shape.call(this);
};

Square と Shape の両方で動作するようにしたい場合instanceofは、何をどのように継承したいかによって、プロトタイプやコンストラクターをいじり始める必要があります。

var Shape = function () {};
Shape.prototype.getArea = function () { return this.length * this.width; };

var Square = function (l) { this.length = l; this.width = l; };
Square.prototype = new Shape();

var Circle = function (r) { this.radius = r; };

Circle.prototype = new Shape();
Circle.prototype.getArea = function () { return 2 * Math.PI * this.radius; };

var circle = new Circle(4),
    square = new Square(4);

circle instanceof Shape; // true
square instanceof Shape; // true

これは単純に、(すべてのインスタンスで再利用される) プロトタイプ オブジェクトを親クラスの新しいインスタンスに設定しているためです。その単一インスタンスをすべての子クラスで共有することもできます。

var shape = new Shape();
Circle.prototype = shape;
Square.prototype = shape;

... をオーバーライドしないでください。.getAreaプロトタイプの継承は public-static メソッドを継承するようなものだからです。

形状はもちろん、それなりshape.__proto__.constructor === Shapeに揃っていsquare.__proto__.constructor === Squareます。関数が指定されたものと一致するかどうかを確認して、リンクを再帰するinstanceofだけです。__proto__

そして、上記の方法で関数を構築している場合 (Circle.prototype = new Shape(); Circle.prototype.getArea = function () { /* overriding Shape().getArea() */};は、それcircle instanceof Circle && circle instanceof Shape自体を処理します。

ミックスイン継承、または疑似コンストラクター ( でないオブジェクトを返すthisなど) はconstructor、これらのチェックを機能させるためにマングリングを必要とします。

...とにかく... #2へ:

上記のすべてを知っていれば、これはすぐに修正できるはずです。

関数自体を作成するのではなく、関数の目的の名前の文字列を作成しており、Obj変数が定義されていないため、「参照エラー」が発生しています。代わりに、「目的の名前」をオブジェクトのプロパティ。

var classes = {},
    class_name = "Circle",

    constructors = [];


classes[class_name] = function (r) { this.radius = r; };

constructors.push(classes.Circle);

var circle = new constructors[0](8);
circle instanceof classes.Circle;

これですべてが適切に定義され、上書きする必要のないものは上書きされず、 のメンバーをサブクラス化してオーバーライド.prototypeすることができ、手続き的な方法 (オブジェクトのプロパティとしてinstanceof代入し、設定する) で行うことができます。data.nameその値をnew Function(data.args, data.constructor)に渡し、そのオブジェクト プロパティをルックアップに使用します)。

これの一部/すべてが役立つことを願っています。

于 2013-02-18T07:21:40.140 に答える