-1

I am trying to write a function that adds logging to any function. Something like:

function loggerise(f) {
   return function() {
      const r = f(...arguments)
      console.log(r)
      return r
   }
}

Except that the above doesn't work.

Tested on this object:

const oracle = {
  question:'',
  ask: function(q) {this.question=q},
  answer: function() {return 'Answer to '+this.question+' is 42'},
  answerLog: loggerise(function() {return 'Answer to '+this.question+' is 42'})
}

oracle.ask('the universe');
alert(oracle.answer()); // correct result, no logging
alert(loggerise(()=>(42))()) // correct result and logging, not in object
alert(oracle.answerLog()); // wrong result and logging, in object

The function gives the result Answer to undefined is 42 which shows that the object's context is lost. I've tried to define the context explicitly but I am getting that wrong:

function loggerise(f) {
   const that = this
   return function() {
      const r = f.apply(that,arguments)
      console.log(r)
      return r
   }
}

Is giving the same wrong result, as do some variants of the same.

JSFiddle: https://jsfiddle.net/boisvert/f3ab8qog/21

boisvert
  • 3,679
  • 2
  • 27
  • 53

1 Answers1

1

You also need to pass over the value of this when calling the function, otherwise you lose the context when calling methods in objects.

You can use the arguments object with:

Function#apply()

function loggerise(f) {
  return function() {
    const r = f.apply(this, arguments);
    console.log(r)
    return r;
  }
}

function loggerise(f) {
  return function() {
    const r = f.apply(this, arguments);
    console.log(r)
    return r;
  }
}

const oracle = {
  question:'',
  ask: function(q) {this.question=q},
  answer: function() {return 'Answer to '+this.question+' is 42'},
  answerLog: loggerise(function() {return 'Answer to '+this.question+' is 42'})
}

oracle.ask('the universe');
console.log(oracle.answer()); 
console.log(loggerise(()=>(42))());
console.log(oracle.answerLog());

Function#call()

function loggerise(f) {
  return function() {
    const r = f.call(this, ...arguments);
    console.log(r)
    return r;
  }
}

function loggerise(f) {
  return function() {
    const r = f.call(this, arguments);
    console.log(r)
    return r;
  }
}

const oracle = {
  question:'',
  ask: function(q) {this.question=q},
  answer: function() {return 'Answer to '+this.question+' is 42'},
  answerLog: loggerise(function() {return 'Answer to '+this.question+' is 42'})
}

oracle.ask('the universe');
console.log(oracle.answer());
console.log(loggerise(()=>(42))());
console.log(oracle.answerLog());

Reflect.apply()

function loggerise(f) {
  return function() {
    const r = Reflect.apply(f, this, arguments);
    console.log(r)
    return r;
  }
}

function loggerise(f) {
  return function() {
    const r = Reflect.apply(f, this, arguments);
    console.log(r)
    return r;
  }
}

const oracle = {
  question:'',
  ask: function(q) {this.question=q},
  answer: function() {return 'Answer to '+this.question+' is 42'},
  answerLog: loggerise(function() {return 'Answer to '+this.question+' is 42'})
}

oracle.ask('the universe');
console.log(oracle.answer());
console.log(loggerise(()=>(42))());
console.log(oracle.answerLog());

There is not much difference between these. It is down to preference which one you pick.

VLAZ
  • 26,331
  • 9
  • 49
  • 67