我是否以字符串形式分配对函数或函数的引用?

时间:2019-06-14 18:20:51

标签: javascript

将函数处理程序分配给变量使我相信我的变量现在是对函数的引用。尽管这一切看起来都很好,但为什么我可以将字符串与我的“引用”连接起来,为什么当我将“引用”写入屏幕时这种连接会得到反映?

为什么我的函数引用既被处理又被写成字符串?

引用和类型在幕后发生了什么?

    <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!”被写入屏幕。

2 个答案:

答案 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;