1

I have been working on some old jsp pages, and am trying to introduce jQuery to it. However, this is what I get when I start using jQuery on the page:

base.js:249 Uncaught TypeError: f is not a function

So obviously there is a conflict between our legacy base.js and jQuery. And here's the code snippet from base.js that caused the issue:

Object.prototype.each = function (f) {
    for (var n = 0; n < this.length; n++)    {
        f (this[n],n);     // This is line 249
    }
    return this;
};

The bad news is that I can't easily refactor this library out of the page because there are a few other JavaScript libraries using it for the page.

Is there anything I can do? Thanks!

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
Hua
  • 666
  • 2
  • 9
  • 21
  • If you're using the minified version of jquery, try using the non-minified version. – Richard Theobald Jan 26 '16 at 18:36
  • find usages of that `each` method and make sure that the function was passed in as an argument – RomanPerekhrest Jan 26 '16 at 18:37
  • 3
    **Never, ever** add an enumerable property to `Object.prototype`. Even adding a non-enumerable one is questionable enough (you've just found out why), but an *enumerable* one will just break all kinds of things. – T.J. Crowder Jan 26 '16 at 18:40
  • What exactly makes you think this is a conflict with jQuery? – Rein Jan 26 '16 at 18:40
  • @T.J.Crowder, sorry there is little I can do about the legacy code. – Hua Jan 26 '16 at 18:53
  • @RomanPerekhrest, that would mean I would have to modify a bunch of other libraries... – Hua Jan 26 '16 at 18:56
  • @Rein, nothing in particular. But the error appears whenever I try to add jQuery. – Hua Jan 26 '16 at 18:56
  • @RichardTheobald. I had tried both the min and the full versions. And I got the same thing. – Hua Jan 26 '16 at 18:56
  • @Hua: Raise it with your manager. As you integrate third-party libraries, this will bite you, and bite you, and bite you, and bite you. You can either fix it now, or die by a thousand cuts. In any case, at the very least, you can make it non-enumerable (unless you need to support IE8 and earlier). That would do a *lot* to mitigate the damage. – T.J. Crowder Jan 26 '16 at 18:58
  • @T.J.Crowder. Sorry for my ignorance. But how can I make it non-enumerable? Is there something you can point me to? Meanwhile, like you said, I will bring this up with my manager. The library was originally written in 2005. People today probably would know better! Thanks so much for your help! – Hua Jan 26 '16 at 19:07
  • @Hua: In ES5 they introduced the [`Object.defineProperty`](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.defineproperty) function, which lets you create properties on objects that are non-enumerable. (In fact, they're non-enumerable by default.) `Object.defineProperty(Object.prototype, "each", { value: function(f) { /*...*/ }});` – T.J. Crowder Jan 26 '16 at 19:20
  • @T.J.Crowder: I have tried your code and don't get the error any longer. But I am not getting the result I want yet -- could be because of my code not working and I am still working on it. So I can use your code without breaking the library, suppose I don't have support IE8 and earlier? – Hua Jan 26 '16 at 19:46
  • @Hua: With that example, every object will still inherit the `each` function as they do with your original code, but `each` won't show up in `for-in` loops or `Object.keys`. So yes, unless you have something relying on that, it should work. – T.J. Crowder Jan 27 '16 at 08:17
  • @T.J.Crowder: Thanks so much for your great help!! I wish I could mark yours as the correct answer! – Hua Jan 27 '16 at 17:22

1 Answers1

2

Quick tip:

This is just a hack job, to solve the issue:

Object.prototype.each = function (f) {
  for (var n = 0; n < this.length; n++) {
    if (typeof f == "function")
      f(this[n],n);     // This is line 249
    else
      console.log("You've got a problem here. The f is " + f);
  }
  return this;
};

The above code might work, as well as help you debug things.

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
  • Thanks for the reply. I have tried your solution, and I got the logging statement. So obviously it was calling the wrong function. – Hua Jan 26 '16 at 19:03
  • @Hua Could you find which calls what function and can you trace your issue to solve it? – Praveen Kumar Purushothaman Jan 26 '16 at 19:06
  • 1
    The call is coming from jquery.dataTables.js (I've tried the min version with pretty much the same result). And here's the snippet: `this.each(function() { // For each initialisation we want to give it a clean initialisation // object that can be bashed around var o = {}; var oInit = len > 1 ? // optimisation for single table case _fnExtend( o, options, true ) : options;...` – Hua Jan 26 '16 at 19:22
  • @Hua Try using the full version of the table script. – Praveen Kumar Purushothaman Jan 26 '16 at 20:36
  • Praveen Kumar: Thanks so much for your kind help! I managed to get things going using the full version of dataTables. However, I did have to make the change that @T.J. Crowder suggested: `Object.defineProperty(Object.prototype, "each", { value: function(f) { /*...*/ }});` I am assuming that such a change does not break the library. – Hua Jan 26 '16 at 22:08
  • Thanks for all the great help!! – Hua Jan 26 '16 at 22:38