【问题标题】:Question about ‘this’ inside higher-order-function's callback关于高阶函数回调中“this”的问题
【发布时间】:2019-09-11 13:08:40
【问题描述】:

我有一个关于 JavaScript 高阶函数回调中的“this”的问题。

我一直在探索以下代码 - 目标是将接受回调的函数转换为返回承诺的函数。 来源: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);
}

现在,作者使用了一个高阶函数,它将接受上述函数作为回调并进行承诺:

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

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

我知道为了追踪回调的“this”指向什么,你需要检查包含它的高阶函数...... 但我不明白为什么在这种情况下我们必须明确声明回调的“this”?

感谢您的帮助!

【问题讨论】:

    标签: javascript callback this higher-order-functions


    【解决方案1】:

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

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

    让我先回答在这种情况下'this'是什么?部分:

    我们不知道(一般情况下),这就是为什么使用.call,但我会解决的。

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

    this 的值取决于如何调用函数promisify 无法知道新的包装函数将如何被调用,也不知道被包装的函数是否使用this。因此,它需要假设this 将很重要,并且必须以正确设置this 的方式调用包装函数。
    调用函数并显式设置this 值的唯一方法是通过.call.apply。如果函数被调用为f(...args),那么f 中的this 将是全局对象或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(...) 不会有什么不同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 2019-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多