Javascript: 编写高阶函数以使用调用它的对象的上下文

Javascript: Write a higher-order function to use the context of the object from which it is called

我正在尝试编写一个向任何函数添加日志记录的函数。类似于:

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

调用函数的时候也需要传过来the value of this,否则调用对象中的方法会丢失上下文

您可以将 the arguments object 用于:

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


这些之间没有太大区别。看你喜欢哪一个。