如果JavaScript有一流函数,为什么在变量中调用该函数不起作用?

22

JavaScript据称拥有一流函数,因此似乎以下内容应该有效:

var f = document.getElementById;
var x = f('x');

但是在所有浏览器上都失败了,并且每个浏览器都显示不同的加密错误信息。Safari 显示“类型错误”。Chrome 显示“非法调用”。Firefox 显示“无法转换 JavaScript 参数”。

为什么?

3个回答

38
当你在Javascript中调用obj.method()时,方法会将obj作为this传递。因此,使用document.getElementById('x')调用会将this设置为document
但是,如果你只写f = document.getElementById,那么你现在有了一个新的函数引用,但是该引用不再与document“绑定”。
所以你的代码无法正常工作,因为当你将f作为裸函数名称调用时,它最终会被绑定到全局对象(window)。一旦函数内部尝试使用this,它发现它现在拥有了一个window而不是一个document,并且毫不奇怪地它会出问题。
如果按如下方式调用f,则可以使其正常工作:
var x = f.call(document, 'x');

这段代码调用了f函数,但明确将上下文设置为document

另一种解决方法是使用Function.bind(),它在ES5及以上版本中可用:

var f = document.getElementById.bind(document);

而实际上,它只是一个通用的快捷方式,用于创建正确设置上下文的自己的包装器:

function f(id) {
    return document.getElementById(id);
}

24

由于在JavaScript中函数并不会 绑定 到上下文 (this)。您可以使用bind()

var f = document.getElementById.bind(document);

4
为了澄清这个答案,“this”在“document.getElementById()”中是“document”,而在执行作用域的位置,“this”是全局作用域,即“this”是“window”对象。 - Andy Ray

4
使用ES6的扩展运算符,你也可以尝试以下方法:
function f(){
    return document.getElementById(...arguments);
};

巴别尔会给出以下代码:
function f() {
    var _document;
    return (_document = document).getElementById.apply(_document, arguments);
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接