Могу ли я скопировать / клонировать функцию в JavaScript? - PullRequest
20 голосов
/ 15 января 2009

Я использую 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 и вызовом валидатора по умолчанию через эту ссылку не имеет значения.

Что мне действительно нужно сделать, так это уметь копировать требуемую функцию валидатора по умолчанию по значению, а не по ссылке. Но после долгих поисков я не могу понять, как это сделать. Возможно ли это?

Если это невозможно, тогда я могу скопировать источник для исходной функции. Но это создает проблему обслуживания, и я бы не стал этого делать, если нет «лучшего способа».

Ответы [ 8 ]

17 голосов
/ 15 января 2009

Хранение ссылки на функцию внешне перед вызовом 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);
9 голосов
/ 30 марта 2010
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 () совершенно глупо и слишком длинно, а конструктор Function примерно такой же. Литералы намного лучше. И в том числе JQuery только для этого, более того, если он не работает должным образом (и я не думаю, что он работает), это не самая яркая вещь, которую вы можете сделать.

5 голосов
/ 21 июля 2011

Вот обновленный ответ

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", который вы указали (пробел {} выше). Будет сохраняться для любых будущих вызовов функции, независимо от переопределения с помощью функций apply () / call ().

Это может быть использовано как в ваших интересах, так и в ущерб, в зависимости от того, как вы справляетесь с этим.

4 голосов
/ 15 января 2009

Я думаю, вам просто не хватает области видимости. Попробуйте это:

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);
3 голосов
/ 19 марта 2014

(это должен быть только комментарий для Могу ли я скопировать / клонировать функцию в JavaScript? ... к сожалению, с rep <50 можно только публиковать) </p>

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();
  • действительно ли это требуется?
  • где клонирование останавливается? являются прототипами также изолированы, так что изменение этих клонированных объектов не влияет экземпляры, не связанные с клонированным объектом? в таком случае клонирование должно пройти весь путь до прототипа цепи к примитивные конструкторы, которые сами должны быть как-то клонирован и изолирован (одна хитрость в браузере заключается в открытии нового окна и заполнении его предупреждением о том, что opener . и т. д. все еще могут пропускать перекрестные эффекты)
2 голосов
/ 12 февраля 2009

, если вы хотите клонировать функцию, попробуйте это:

Function.prototype.clone=function(){
    return eval('['+this.toString()+']')[0];
}
1 голос
/ 15 января 2009

Звучит так, как будто нет лучшего способа. Я полагаю, вы могли бы попытаться сделать пользовательскую требуемую функцию для своей собственной, например:

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

Звучит так, будто вы уже пробовали все остальное. Извиняюсь, если я неправильно понял вопрос.

0 голосов
/ 09 июня 2009

Отвечая на предыдущий пост, когда мне нужно поделиться функцией конструктора, сохраняя отдельный прототип, я использую оболочку в новой функции:

`

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...