2016-10-18 3 views
1

私はデータベースから取り出した記述的なデータに基づいてクラスを動的に構築しています。例えば、データがこのよう読み込む場合:手動でextend/superを実装する

ClassName = ExampleParent 
Method1.name = "greet" 
Method1.code = "console.log(\"Parent hello\");" 

とこのようにそれを構築するだけで正常に動作:

classList[ClassName] = function(){} 
classList[ClassName].prototype[Method1.name] = Function(Method1.code); 

var Bob = new classList["ExampleParent"](); 
Bob.greet(); 

しかし、私は、動的に継承を作成する方法について困惑:

ClassName = ExampleChild 
ClassExtends = ExampleParent 
Method1.name = "greet" 
Method1.code = "super.greet(); console.log(\"Child hello\");" 

私はどのように使用できるかわかりませんExampleChild.prototypeはExampleParentとExampleChildのカスタムメソッドの両方を指していますが、試してみてもsuperは不明でした。私は空想的なもの(プライベート、静的など)をサポートする必要はありません... このスーパーが必要です。ヒント?

+1

あなたはあなたのJavaScriptコードは、現在生成されて表示されことができますか?また、 'super'はES6と' class ClassName extends Object'構文の中で宣言された関数の中でのみ利用可能です。 –

+0

お詫び申し上げます。私は今、第1の例のJavaScriptコードを参照しています。 –

+0

@HeinrichHenning:奇妙なことに、オブジェクト初期化子でも 'super'を使うことができます。 [例、ちょうど楽しみのため](https://jsfiddle.net/cmw3L31v/) –

答えて

0

残念ながら、あなたが(仕事をする関数を返しFunction持つことや効果的evalを使用して)evalを使用せずにすることはできませんが、Functionはちょうどevalのように任意のコードの実行を許す限りそれはあなたがやっていることと一致してまだですそうです。それでも、醜いです。

データの送信元を絶対に信頼することが重要です。eval(およびFunction)は任意のコードの実行を許可しているため、がユーザーユーザーAを信頼することなく、ユーザーAがデータベースに格納されたコードを書き込んで使用することを許可してはいけません。

const className = "ExampleChild"; 
const parentName = "ExampleParent"; 
const methodName = "greet"; 
const methodCode = "super.greet();"; 
const C = eval(` 
    class ${className} extends ${parentName} { 
     ${methodName}() { 
      ${methodCode} 
     } 
    }` 
); 

あなたはクラスを格納するオブジェクトを必要とするかもしれない:リスクのユーザB、潜在的な場所でその警告したユーザーA.

から悪意のあるコードにさらす、あなたは例えば、evalでそれを行うことができます実行時の名前でオンにします。これは、extends claに必要なものですつかいます。

例:

const classes = {}; 
 
function buildClass(spec) { 
 
    const extendsClause = spec.parentName ? ` extends classes.${spec.parentName}` : ""; 
 
    const methods = spec.methods.map(
 
     mspec => `${mspec.name}() { ${mspec.code} }` 
 
    ).join("\n"); 
 
    const cls = classes[spec.className] = eval(` 
 
     class ${spec.className} ${extendsClause} { 
 
      ${methods} 
 
     }` 
 
    ); 
 
    return cls; 
 
} 
 

 
const specs = [ 
 
    { 
 
     className: "ExampleParent", 
 
     methods: [ 
 
      {name: "greet", code: "console.log(\"Parent hello\");"} 
 
     ] 
 
    }, 
 
    { 
 
     className: "ExampleChild", 
 
     parentName: "ExampleParent", 
 
     methods: [ 
 
      {name: "greet", code: "super.greet(); console.log(\"Child hello\");"} 
 
     ] 
 
    } 
 
]; 
 

 
specs.forEach(buildClass); 
 

 
let c = new classes.ExampleChild(); 
 
c.greet();

+0

@Bergi:Yikes、なぜ私の後脳は「?」と言っていたのですか?ありがとう。 –

+0

うーん、まっすぐ前方に見える、このショットを与えるだろう。 Nodeでこれをサンドボックスする方法に関するアドバイスはありますか?現在、「信頼できない」コードはすべて私によって書かれていますが、それが安全であることが分かっていれば、長期的に他の人にも公開したいと思います。 – JeramieH

+0

@JeramieH簡単にはできません(と非常に広いトピック)。あなたが信頼する人のコードを実行するほうがよいでしょう。 – Bergi

-1

あなたはサブクラスのプロトタイプの内部superというプロパティを作成し、スーパークラスのインスタンスでそれを設定することができます。

は、この例を見てみましょう:

// -- Base Structure - This code is fixed, hard coded -- 
 
var classList = {}; 
 

 
// Register a new class 
 
function registerClass(definition) { 
 
    var cls, i, method; 
 

 
    cls = function() {}; 
 

 
    if (definition.superClass) { 
 
    cls.prototype.super = new classList[definition.superClass](); 
 
    } 
 

 
    classList[definition.name] = cls; 
 
    cls.constructor = cls; 
 

 
    for (i = 0; i < definition.methods.length; i++) { 
 
    method = definition.methods[i]; 
 
    cls.prototype[method.name] = Function(method.code); 
 
    } 
 
} 
 

 

 
// -- Here you need to get data from your database -- 
 

 
// Super Class 
 
registerClass({ 
 
    name: "SuperClass", 
 
    methods: [{ 
 
    name: "greet", 
 
    code: "console.log(\"Super hello\");" 
 
    }] 
 
}); 
 

 

 
// Sub Class 
 
registerClass({ 
 
    name: "SubClass", 
 
    superClass: "SuperClass", 
 
    methods: [{ 
 
    name: "greet", 
 
    code: "this.super.greet(); console.log(\"Sub hello\");" 
 
    }] 
 
}); 
 

 

 
// Usage 
 
var obj = new classList.SubClass(); 
 
obj.greet();

関連する問題