首页 > 解决方案 > Javascript:编写一个高阶函数以使用调用它的对象的上下文

问题描述

我正在尝试编写一个将日志记录添加到任何函数的函数。就像是:

function loggerise(f) {
   return function() {
      const r = f(...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');
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

该函数给出的结果Answer to undefined is 42表明对象的上下文丢失了。我试图明确定义上下文,但我弄错了:

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

给出了同样的错误结果,同样的一些变体也是如此。

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

标签: javascripthigher-order-functions

解决方案


您还需要在调用函数时传递this,否则在调用对象中的方法时会丢失上下文。

您可以arguments对象用于:

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


这些之间没有太大区别。这取决于您选择哪一个。


推荐阅读