web-dev-qa-db-ja.com

JavaScriptで関数をコピー/クローンできますか?

バリデータプラグインでjQueryを使用しています。 「必須」のバリデーターを自分のものに交換したいと思います。これは簡単:

jQuery.validator.addMethod("required", function(value, element, param) {
    return myRequired(value, element, param);
}, jQuery.validator.messages.required);

ここまでは順調ですね。これは問題なく機能します。しかし、私が本当にやりたいのは、場合によっては関数を呼び出し、残りはデフォルトのバリデーターを呼び出すことです。残念ながら、これは再帰的であることが判明しました。

jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return jQuery.validator.methods.required(value, element, param);
}, jQuery.validator.messages.required);

バリデーターのソースコードを調べたところ、「required」のデフォルトの実装は、jQuery.validator.messages.requiredで匿名メソッドとして定義されています。したがって、私が使用できる関数への(匿名ではない)他の参照はありません。

AddMethodを呼び出す前に関数への参照を外部に保存し、その参照を介してデフォルトのバリデーターを呼び出すことには違いはありません。

私が本当にする必要があるのは、デフォルトで必要なバリデーター関数を参照ではなく値でコピーできるようにすることです。しかし、かなりの検索の後、私はそれを行う方法を理解することができません。出来ますか?

それが不可能な場合は、元の関数のソースをコピーできます。しかし、それはメンテナンスの問題を引き起こし、「より良い方法」がない限り、私はむしろそれをしたくありません。

20
Craig Stuntz

AddMethodを呼び出す前に関数への参照を外部に保存し、その参照を介してデフォルトのバリデーターを呼び出すことには違いはありません。

それはまさにそれです動作するはずです

jQuery.validator.methods.oldRequired = jQuery.validator.methods.required;

jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return jQuery.validator.methods.oldRequired(value, element, param);
}, jQuery.validator.messages.required);

これも機能するはずです:(そしてthisの問題は解決されました)

var oldRequired = jQuery.validator.methods.required;
jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return oldRequired.call(this, value, element, param);
    // return jQuery.oldRequired.apply(this, arguments);
}, jQuery.validator.messages.required);
18
Georg Schölly
Function.prototype.clone = function() {
    var fct = this;
    var clone = function() {
        return fct.apply(this, arguments);
    };
    clone.prototype = fct.prototype;
    for (property in fct) {
        if (fct.hasOwnProperty(property) && property !== 'prototype') {
            clone[property] = fct[property];
        }
    }
    return clone;
};

唯一の悪い点は、プロトタイプが複製されていないため、実際に変更できないことです...私はあらゆるタイプのオブジェクトを複製する方法に取り組んでおり、RegExpに任せています。だから私はおそらく明日編集してコード全体を配置します(これはちょっと長く、関数とオブジェクトにのみ使用する場合は最適化されません。

そして、他の答えをコメントするために、eval()を使用することは完全に愚かで、長すぎて、関数コンストラクターは同じようなものです。 Literralsははるかに優れています。そして、そのためだけにJQueryを含めると、さらに、それが適切に機能しない場合(そして、私はそれが機能するとは思わない)、あなたができる最も明るいことではありません。

9
xavierm02

これが更新された答えです

var newFunc = oldFunc.bind({}); //clones the function with '{}' acting as it's new 'this' parameter

ただし、.bindはJavaScriptの新機能ですが、Mdnからの回避策があります。

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

さらに、関数の追加プロパティのクローンを作成しません。

注:@ gsnedderが指摘したように:バインドされたステートメント、「this」引数uが提供されました(上記の空白{})。 apply()/ call()関数によるオーバーライドに関係なく、関数の今後の呼び出しに対して存続します。

これは、対処方法に応じて、有利にも不利にも使用できます。

5
PicoCreator

私はあなたがほんの少しのスコープを逃していると思います。これを試して:

jQuery.validator.methods._required = jQuery.validator.methods.required;
jQuery.validator.addMethod("required", function(value, element, param) {
    // handle comboboxes with empty guids
    if (someTest(element)) {
        return myRequired(value, element, param);
    }
    return jQuery.validator.methods._required.call(this, value, element, param);
}, jQuery.validator.messages.required);
4
Crescent Fresh

(これは JavaScriptで関数をコピー/クローンできますか? ...残念ながら、rep <50の場合は投稿のみ可能です)

Function.prototype.clone=function(){
    return eval( '('+this.toString()+')' );
}

十分、あるいは

Object.prototype.clone=function(){
    return eval( '('+this.toString()+')' );
}

効率についての考え:

  • 機械の「寿命」を最適化または改善するために人的資源を浪費するよりも、人的効率がはるかに重要です。
  • コンピュータと自動化されたシステムは、人間の努力を増やすのではなく減らすことになっています
  • 計算のオーバーヘッドは、多くの人が結果の人間の消費に対する嗜好性に深刻な影響を与える必要があります。これは、コードの最適化に投資する努力を正当化するためです。ロジックを「理解」する

クローン作成について:この質問は非常に修辞的である可能性があります

  • javascriptオブジェクトを「複製」するとはどういう意味ですか?特に再帰関数理論の文脈で
    • クローニングを合理化するための一般的なテーマは、ドッペルゲンガーの変更からオリジネーターを分離して「保護」することです。
    • a = new Object(); b = new Object();aおよびbクローンの場合? o = Object; a = new o(); b = new o();はどうですか
  • 本当に必要ですか?
  • クローン作成はどこで停止しますか?複製されたオブジェクトがこれらを変更しても、複製されたオブジェクトに関連付けられていないインスタンスに影響を与えないように、プロトタイプの属性も分離されますか?この場合、クローン作成は、プロトタイプチェーンを上って、何らかの方法でクローン作成して分離する必要があるプリミティブコンストラクターに到達する必要があります(ブラウザーでの1つのトリックは、新しいウィンドウを開いて、opener .などができる警告を再入力することです。それでもクロスエフェクトをリークします)
4
ekim

関数のクローンを作成したい場合は、これを試してください:

Function.prototype.clone=function(){
    return eval('['+this.toString()+']')[0];
}
2
carrilho joakim

「より良い方法」はないようです。私はあなたがあなた自身のためにカスタム必須関数を作ってみることができると思います例えば:

jQuery.validator.addMethod("customRequired", function(value, element, param) {
  return myRequired(value, element, param);
}, jQuery.validator.messages.required);

あなたはすでに他のすべてを試したようですね。質問を誤解してしまったらお詫びします。

1
roborourke

前の投稿に答えて、コンストラクター関数を共有する必要がある場合、別個のプロトタイプを維持しながら、新しい関数でラッパーを使用します。

`

init_from_arg_obj = function () {
    return new Function('init', 'for (var i in init) this[i] = init[i];');
};

constructor_A = init_from_arg_obj();
constructor_A.prototype = {a: 'A'};

constructor_B = init_from_arg_obj();
constructor_B.prototype = {b: 'B'};

`

いくつかのテストを実行して、これが優れたJSエンジンでの実行を遅くしないことを確認します。

0
Max_B