将函数处理程序分配给变量使我相信我的变量现在是对函数的引用。尽管这一切看起来都很好,但为什么我可以将字符串与我的“引用”连接起来,为什么当我将“引用”写入屏幕时这种连接会得到反映?
为什么我的函数引用既被处理又被写成字符串?
引用和类型在幕后发生了什么?
<button id="test_button">Press Me</button>
<br>
<p id="test_p"></p>
<script>
var x = tester;
document.getElementById("test_button").onclick=x;
document.getElementById("test_p").innerHTML+=(x+"<br>");
x+="Did I just concatenate a string?";
document.getElementById("test_p").innerHTML+=(x);
function tester()
{
document.write("Hello World!");
}
</script>
我将引用分配为按钮的onclick,并且该功能仍按预期执行。
[Press Me]
function tester() { document.write("Hello World!"); }
function tester() { document.write("Hello World!"); }Did I just concatenate
a string?
上面输出,并且当按下按钮时,“ Hello World!”被写入屏幕。
答案 0 :(得分:1)
为什么我可以将字符串与“引用”连接起来
因为当将运算符应用于运算符不支持的数据类型的值时,JavaScript会执行类型转换。没有为函数定义串联运算符(+
),因此该函数首先转换为字符串。
用户定义函数的字符串表示形式是其源代码。
当我在屏幕上写“引用”时为什么会反映这种串联?
因为x += y
(和.innerHTML += y
)与x = x + y
相同。您正在执行字符串连接,并将新值(字符串)分配回x
(.innerHTML
)。 x
用于保存一个函数,该操作之后将保存一个字符串。
为什么我的函数引用既被处理又被写成字符串?
不是。当您执行document.getElementById("test_button").onclick
(或x += ...
)时,.innerHTML += ...
的值不会改变。
当你这样做
document.getElementById("test_button").onclick = x
您已将x
的当前值分配给element.onclick
。此时x
的值是对函数的引用。
当您执行x += ...
时,会为x
分配一个新值,但这不会更改onclick
属性的值。
我们从
开始 +---------------+
| |
x: ref ---------------->|function tester|
| |
+---------------+
分配给.onclick
后,我们有
+---------------+
| |
x: ref ------------------------>|function tester|
| |
+---------------+
^
|
element.onclick: ref ------------------+
在将串联字符串分配给x
之后,我们有了
+---------------+
| |
|function tester|
| |
x: string "function tester()...." +---------------+
^
|
element.onclick: ref ----------------------------+
引用和类型在幕后发生了什么?
参考文献实际上与这里没有任何关系。 JavaScript中的对象是reference type values,但与其他语言不同,您可以访问引用或引用的值。这一切都在幕后发生。
答案 1 :(得分:0)
可以通过调用Function.toString()
来对函数进行字符串化。连接时(从+
运算符到字符串操作数),从函数到字符串的类型强制转换会自动发生。
Function.prototype.toString()
的MDN参考状态:
对于用户定义的
Function
对象,toString
方法返回一个字符串,其中包含用于定义函数的源文本段。当将
Function
表示为文本值时,例如,JavaScript自动调用toString
方法。当函数与字符串连接时。
在设置.onclick
或.innerHTML
属性的情况下,会将功能对象本身分配给该属性。区别在于.innerHTML
最终通过调用fn.toString()
来对函数进行字符串化,而.onclick
则将该函数作为回调来调用。
您可以将console.log
插入函数的toString
中,以验证在设置innerHTML
或执行串联操作时确实调用了该函数:
const foo = () => "hello";
foo.toString = () => console.log("toString called!") || "this is the toString() string";
42 + foo; // was toString really called?
const div = document.createElement("div");
document.body.appendChild(div);
div.innerHTML = foo; // was toString really called?
...但在设置或调用onclick
时不是:
const foo = () => console.log("hello");
foo.toString = () => console.log("toString called!") || "this is the toString() string";
const btn = document.createElement("button");
document.body.appendChild(btn);
btn.innerText = "click me to see if toString is called";
btn.onclick = foo;