我正在尝试“Javascript -权威指南”第8章函数中的示例。在第8节。3.4“函数调用的扩展运算符”,代码是可行的:
function timed(f) {
return function(...args) {
console.log(`Entering function ${f.name}`);
let startTime = Date.now();
try {
return f(...args);
}
finally {
console.log(`Exiting ${f.name} after
${Date.now()-startTime}ms`);
}
};
}
function benchmark(n) {
let sum = 0;
for(let i = 1; i <= n; i++) sum += i;
return sum;
}
timed(benchmark)(1000000);
控制台输出为:
Entering function benchmark
Exiting benchmark after 46ms
在第8节。7.4“The call()and apply()Methods”,函数timed()被更改为trace(),我无法让代码工作:
function trace(o, m) {
let original = o[m];
o[m] = function(...args) {
console.log(new Date(), "Entering:", m);
let result = original.apply(this, args);
console.log(new Date(), "Exiting:", m);
return result;
};
}
trace(benchmark)(1000000);
抛出此错误:
未捕获的类型错误:trace(...)不是函数
我尝试了几个变种,但都不起作用:
benchmark.trace(1000000);
trace.benchmark(1000000);
benchmark.call(trace, 1000000);
obj = {};
trace(obj, benchmark(1000000));
我做了一个检查:
console.log(typeof trace);
输出表明trace()是一个函数。..
有人能解释一下trace()应该如何与benchmark()一起使用吗?我是否需要创建新的对象或函数?
这本书只提供了这样的提示:
下面定义的trace()函数类似于§8中定义的timed()函数。3.4,但它适用于方法而不是函数。它使用apply()方法而不是spread运算符,通过这样做,它能够调用 Package 方法,并使用与 Package 方法相同的参数和相同的this值:
// Replace the method named m of the object o with a version that logs
// messages before and after invoking the original method.
function trace(o, m) { ...
2条答案
按热度按时间8aqjt8rx1#
因此,更新后的方法
trace
应该接受一个对象(o
)和该对象上的一个方法(m
),它的设计目的是用基准测试功能来装饰该方法。下面是如何使用它:
我们可以进一步分解它是如何工作的
当传入对象和方法名时,上面的一行捕获一个局部变量,并带有指向该函数的指针
上面的部分用一个指向新函数的指针替换对象上的那个函数
上面的一行调用原始函数(using
apply
),并传递了参数。您会注意到,is的顶部和尾部是console.log
,您使用它来查看方法何时进入和退出。最后,新附加的方法返回调用original
方法的结果。wnavrhmk2#
重要的是,代码示例使用的是函数表达式语法,而不是箭头函数表达式语法。如果你使用箭头函数,并且原始函数使用“this”关键字,这将不起作用,因为this的值将接受词法作用域并表示外部作用域中this的值,在这个例子中,严格模式下将是未定义的,而在非严格模式下将是全局对象。
通过使用带有function关键字的函数表达式语法,this的值是接收者,在本例中是myObject。现在,apply完全可以将未定义的值作为其第一个参数。在这个例子中,这并不重要,因为原始函数没有使用this关键字,但如果它使用了,你可能会在使用它时出错或意外结果: