关于高阶函数回调中‘this’的问题
Question about ‘this’ inside higher-order-function's callback
我有一个关于 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);
}
现在,作者使用了一个高阶函数,它将接受上述函数作为回调并进行 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(这个, ...args); ?
在这种情况下,“this”是什么?
为什么我们不能这样称呼它:f(...args); ?
我知道为了追踪回调的“this”指向什么,您需要检查包含它的高阶函数...
但我不明白为什么在这种情况下我们必须明确说明回调的“this”?
感谢您的帮助!
Why do we call the f function in this way: f.call(this, ...args);
?
What will ‘this’ be in this case? Why can't we just call it like this: f(...args);
?
让我先回答 在这种情况下“这”是什么? 第一部分:
我们不知道(总的来说),这就是为什么使用 .call
,但我会说的。
promisify
应该“无缝地”包装现有函数。这意味着调用 f
或 promisify(f)
应该 return 相同的结果。
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, ...)
或 [=32= 不会有什么不同]被使用了。
我有一个关于 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);
}
现在,作者使用了一个高阶函数,它将接受上述函数作为回调并进行 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(这个, ...args); ?
在这种情况下,“this”是什么? 为什么我们不能这样称呼它:f(...args); ?
我知道为了追踪回调的“this”指向什么,您需要检查包含它的高阶函数... 但我不明白为什么在这种情况下我们必须明确说明回调的“this”?
感谢您的帮助!
Why do we call the f function in this way:
f.call(this, ...args);
?What will ‘this’ be in this case? Why can't we just call it like this:
f(...args);
?
让我先回答 在这种情况下“这”是什么? 第一部分:
我们不知道(总的来说),这就是为什么使用 .call
,但我会说的。
promisify
应该“无缝地”包装现有函数。这意味着调用 f
或 promisify(f)
应该 return 相同的结果。
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, ...)
或 [=32= 不会有什么不同]被使用了。