我对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”?
谢谢您的帮助!
答案 0 :(得分:1)
为什么我们要这样调用f函数:
f.call(this, ...args);
?在这种情况下,“此”将是什么?为什么我们不能这样称呼它:
f(...args);
?
让我回答在这种情况下,“这是什么?” 首先:
(通常)我们不知道,这就是为什么使用.call
的原因,但是我会明白的。
promisify
应该“无缝”包装现有功能。这意味着调用f
或promisify(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(...)
被使用,则不会有什么不同使用。