0

I've made a little method to easily repeat a function several times (instead of using loops, cause they are long and tiring, at least for me).

Function.prototype.repeat = function(count,params) {
while(count--) this.apply(this, params);
};

document.write.repeat(4,["Hi"]);

I expected it to execute nicely and write it properly. Well, in the line of the while loop, there was an error!!

Uncaught TypeError: Illegal invocation.

Any ideas about what could cause that?

James Montagne
  • 77,516
  • 14
  • 110
  • 130
  • 4
    _"instead of using loops"_. What do you think `while(...)` is? – j08691 Mar 11 '15 at 17:30
  • @j08691 but this will be in a "library" that i will include using ` – The SuperCuber Mar 11 '15 at 17:31
  • `document.write` expects `document` to be its `this` context. But you're invoking it with with `document.write` as `this`. – mbcrute Mar 11 '15 at 17:41
  • possible duplicate of [why can't you do \[array\].forEach(console.log)](http://stackoverflow.com/questions/28974228/why-cant-you-do-array-foreachconsole-log) – JLRishe Mar 11 '15 at 17:43

2 Answers2

4

The context of document.write must be document, so your lib call to .repeat won't work on functions like document.write or console.log unless you account for a parameter to specify the context, or have already bound a context.

Function.prototype.repeat = function(ctx, count, params) {
    //                               ^^^
    while(count--) this.apply(ctx, params);
    //                        ^^^
};

document.write.repeat(document, 4, ["Hi"]);
//                    ^^^^^^^^

or alternatively:

Function.prototype.repeat = function(count, params) {
    while(count--) this.apply(this, params);
};
document.write.bind(document).repeat(4, ["Hi"]);
//            ^^^^^^^^^^^^^^^
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • Thank you very much, I'll use the first option with the `ctx`. Is there an option to make the default ctx equal to `document` (and make it the 3rd parameter) and will it work for all the other functions?(For example alert) – The SuperCuber Mar 11 '15 at 17:57
  • 2
    @TheSuperCuber, you can write it however you'd like, as you're probably the only one who will be using it. I can tell you that a default context of `document` is a terrible choice, but so is creating a `repeat` function on `Function.prototype`. – zzzzBov Mar 11 '15 at 18:05
  • basically what i want is an easy way to repeat a certain command a couple of times. Normally you would need to do `for(var i=0; i<5; i++)` for example, and using repeat it would be really quick and nice :D – The SuperCuber Mar 11 '15 at 20:30
0

A lot of functions rely on being invoked in the context of a particular object in order to work correctly, and document.write is one of those functions. For example, this will fail because any this references within the function will be using the wrong this instead of document:

var w = document.write;
w("hello");

If you correctly invoke it in the context of document, it will work:

Function.prototype.repeat = function(count) {
    while(count--) this.apply(this, Array.prototype.slice.call(arguments, 1));
};

document.write.bind(document).repeat(4, "Hi");

See also: why can't you do [array].forEach(console.log)

Community
  • 1
  • 1
JLRishe
  • 99,490
  • 19
  • 131
  • 169