有关高阶函数回调中的“ this”的问题

时间:2019-09-11 13:08:40

标签: javascript callback this higher-order-functions

我对JavaScript高阶函数的回调中的“ this”有疑问。

我一直在探索以下代码-目标是将接受回调的函数转换为返回promise的函数。 来源:https://javascript.info/promisify

接受回调的函数:

function loadScript(src, callback) {
  let script = document.createElement('script');
  script.src = src;

  script.onload = () => callback(null, script);
  script.onerror = () => callback(new Error(`Script load error for ${src}`));

  document.head.append(script);
}

现在,作者使用一个更高阶的函数,该函数将接受上述函数作为回调并进行promisification:

function promisify(f) {
  return function (...args) { 
    return new Promise((resolve, reject) => {
      function callback(err, result) { 
        if (err) {
          return reject(err);
        } else {
          resolve(result);
        }
      }

      args.push(callback); 

      f.call(this, ...args); 
    });
  };
};

// usage:

let loadScriptPromise = promisify(loadScript);
loadScriptPromise('path/script.js').then(...);

我不明白的是:

为什么我们用这种方式调用f函数: f.call(this,... args); 吗?

在这种情况下,“此”将是什么? 我们为什么不能这样称呼它: f(... args);

我知道,为了追踪“此”回调所指向的内容,您需要检查其中包含的高阶函数... 但是我不明白为什么在这种情况下我们必须明确说明回调的“ this”?

谢谢您的帮助!

1 个答案:

答案 0 :(得分:1)

  

为什么我们要这样调用f函数:f.call(this, ...args);

     

在这种情况下,“此”将是什么?为什么我们不能这样称呼它:f(...args);

让我回答在这种情况下,“这是什么?” 首先:

(通常)我们不知道,这就是为什么使用.call的原因,但是我会明白的。

promisify应该“无缝”包装现有功能。这意味着调用fpromisify(f)应该返回相同的结果。

this的值取决于如何调用函数。 promisify不知道将如何调用新包装器函数,也不知道包装后的函数是否使用this。因此,需要假设this有意义,并且必须以正确设置this的方式调用包装的函数。
调用函数并显式设置this值的唯一方法是通过.call.apply。如果将函数称为f(...args),则this内的f将是全局对象或undefined

这是一个更简单的包装函数,用于演示问题:

function wrapWithThis(f) {
  return function(...args) {
    f.call(this, ...args);
  }
}

function wrapWithoutThis(f) {
  return function(...args) {
    f(...args);
  }
}

function wrapMe() {
  console.log(this.foo);
}

const obj = {
  foo: 42,
  withThis: wrapWithThis(wrapMe),
  withoutThis: wrapWithoutThis(wrapMe),
};

obj.withThis();
obj.withoutThis();


已经针对您的示例进行了所有说明,假设loadScript不使用this,则如果f.call(this, ...)f(...)被使用,则不会有什么不同使用。