Can I copy/clone a function in JavaScript?

30,557

Solution 1

Storing a reference to the function externally before calling addMethod and calling the default validator via that reference makes no difference.

That's exactly what should work.

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 should work too: (And the problem with this is solved)

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);

Solution 2

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;
};

The only bad thing with that is that the prototype isn't cloned so you can't really change it... I'm working on a way to clone any type of objects and I just have RegExp left to do. So I'll probably edit tomorrow and put the entire code (which is kind of long and isn't optimised if you only use it for functions and objects.

And to comment other answers, using eval() is totaly stupid and is way too long and the Function constructor is kind of the same. Literrals are much better. And including JQuery just for that, moreover if it doesn't work properly (and I don't think it does) isn't the brightest thing you can do.

Solution 3

Here is an updated answer

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

However .bind is a new feature of JavaScript there is however a workaround from Mdn

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

Additionally it does not clone the function additional properties.

Note: As @gsnedder pointed out : the bound statement, "this" argument u supplied (blank {} above). Will persist for any future calls of the function, regardless of over-riding via the apply()/call() functions.

This can be used both to your advantage, or disadvantage depending on how you deal with it.

Solution 4

(this should only be a comment for Can I copy/clone a function in JavaScript? ... unfortunately with rep < 50 can only post)

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

suffices, or even

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

thoughts on efficiency:

  • human efficiency is far more important than squandering human resources to optimize or improve a machine's "life"
  • computers and automated systems are supposed to reduce human effort not increase it
  • computational overhead must severely impact a result's palatability for human consumption, by many many people, to justify investing effort in optimizing code that often becomes more obscure, arcane and so esoteric that it can no longer be understood by a stable of programmers after hours of trying to "comprehend" the logic

on cloning: this question can be quite rhetorical

  • what does it mean to "clone" a javascript object? especially in the context of recursive function theory
    • a common theme to rationalize cloning is that it isolates and "protects" an originator from its doppelgänger changes
    • if a = new Object(); b = new Object(); are a and b clones? how about o = Object; a = new o(); b = new o();
  • is it really required?
  • where does cloning stop? are the prototypical attributes to be isolated also so a cloned object's change of these does not affect instances not associated with the cloned object? in which case cloning must go all the way up the prototypical chain to the primitive constructors which themselves would need to be somehow cloned and isolated (one trick in a browser is to open a new window and repopulate it with the caveat that opener . etc. can still leak cross-effects)

Solution 5

I think you're just missing a bit of scoping. Try this:

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);
Share:
30,557
Kevin Gauthier
Author by

Kevin Gauthier

I like all programming languages, except R.

Updated on July 09, 2022

Comments

  • Kevin Gauthier
    Kevin Gauthier almost 2 years

    I'm using jQuery with the validators plugin. I would like to replace the "required" validator with one of my own. This is easy:

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

    So far, so good. This works just fine. But what I really want to do is call my function in some cases, and the default validator for the rest. Unfortunately, this turns out to be recursive:

    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);
    

    I looked at the source code for the validators, and the default implementation of "required" is defined as an anonymous method at jQuery.validator.messages.required. So there is no other (non-anonymous) reference to the function that I can use.

    Storing a reference to the function externally before calling addMethod and calling the default validator via that reference makes no difference.

    What I really need to do is to be able to copy the default required validator function by value instead of by reference. But after quite a bit of searching, I can't figure out how to do that. Is it possible?

    If it's impossible, then I can copy the source for the original function. But that creates a maintenance problem, and I would rather not do that unless there is no "better way."

  • Kevin Gauthier
    Kevin Gauthier over 15 years
    It fixes the recursion (given that, not sure why mine didn't, as I used "var oldRequired" instead of j.v.m.oldrequired" but was otherwise identical, but "this" is now wrong inside oldRequired. I'll work on that, but thanks, I think I'm on the right track now.
  • Kevin Gauthier
    Kevin Gauthier over 15 years
    crescentfresh's tip fixes "this."
  • Stefan
    Stefan over 15 years
    But it's not a nice solution. The best would be to use 'var oldRequired' (no idea why it doesn't work!) and oldRequired.call(jQuery.validator.methods, …, …, …)
  • gsnedders
    gsnedders about 11 years
    However, it relies upon you always wanting to call the function with the same thisArg.
  • PicoCreator
    PicoCreator about 11 years
    @gsnedders : Not really, the this argument for the cloned function, can be defined. Its the first parameter of bind function. However this can be a double edge sword. While it forces a consistency of "this" to a single pre-defined object, regardless on how you pass and execute the function. You are unable to revert back the "this" argument to the object you are calling from (assuming its different). Unless you over-ride it again, with apply(). At the end, options are good, as long as you know what you are doing. And how your function was made, this should not be an issue.
  • gsnedders
    gsnedders about 11 years
    Right, it can be defined. As I said, "with the same". You cannot however override it with apply as a bound function always uses the bound this.
  • PicoCreator
    PicoCreator about 11 years
    @gsnedders : Point taken, tested it, and you are right with the apply not over-riding (chrome). Updated the answer to make this rather important point more obvious.