javascript - 为什么 function.toString() 输出 "[native code]",而登录到控制台直接显示函数的源代码?

标签 javascript function tostring console.log

我决定为 YouTube 实时聊天创建一个用户脚本。这是代码:

const toString = Function.prototype.toString

unsafeWindow.setTimeout = function (fn, t, ...args) {
    unsafeWindow.console.log(fn, fn.toString(), toString.call(fn))
    unsafeWindow.fns = (unsafeWindow.fns ?? []).concat(fn)
    return setTimeout(fn, t, ...args)
}
现在看看输出是什么样子的:
enter image description here
一些函数的输出是可以预测的,但看看其他的!当你做 console.log它,你会看到函数体,但如果你调用 fn.toString() ,您将看到 function () { [native code] } .
但为什么?该脚本在页面之前加载,因此 YouTube 的脚本无法替换这些方法。

最佳答案

这是因为那些函数已经传递给 Function.prototype.bind .

> (function () { return 42; }).toString()
'function () { return 42; }'
> (function () { return 42; }).bind(this).toString()
'function () { [native code] }'
bind方法将任意函数对象转换为所谓的绑定(bind)函数。调用绑定(bind)函数与调用原始函数具有相同的效果,除了 this参数和一定数量的初始位置参数(可能为零)将具有在创建绑定(bind)函数时固定的值。功能上,bind主要相当于:
Function.prototype.bind = function (boundThis, ...boundArgs) {
    return (...args) => this.call(boundThis, ...boundArgs, ...args);
};
当然,上面的内容会在字符串转换后产生不同的值。根据 ECMA-262 11th Ed., §19.2.3.5 ¶2,绑定(bind)函数被指定为具有与 native 函数相同的字符串转换行为。 :

2. If func is a bound function exotic object or a built-in function object, then return an implementation-dependent String source code representation of func. The representation must have the syntax of a NativeFunction. […]

[…]

NativeFunction:

function PropertyName [~Yield, ~Await] opt ( FormalParameters [~Yield, ~Await] ) { [native code] }


当直接将函数打印到控制台(而不是字符串化)时,实现不受任何规范的约束:它可以以任何它希望的方式在控制台中呈现函数。 Chromium 的控制台,当被要求打印绑定(bind)函数时,为了方便起见,只显示原始未绑定(bind)函数的源代码。

证明这确实是在 YouTube 的案例中发生的事情有点麻烦,因为 YouTube 的 JavaScript 被混淆了,但并不是非常困难。我们可以打开 YouTube 的主站点,然后进入开发者控制台并安装我们的陷阱:
window.setTimeout = ((oldSetTimeout) => {
    return function (...args) {
        if (/native code/.test(String(args[0])))
            debugger;
        return oldSetTimeout.call(this, ...args);
    };
})(window.setTimeout);
我们应该在 debugger 上获得成功。声明非常快。我在这个函数中击中了它:
g.mh = function(a, b, c) {
    if ("function" === typeof a)
        c && (a = (0, g.D)(a, c));
    else if (a && "function" == typeof a.handleEvent)
        a = (0, g.D)(a.handleEvent, a);
    else
        throw Error("Invalid listener argument");
    return 2147483647 < Number(b) ? -1 : g.C.setTimeout(a, b || 0)
}
g.D函数看起来特别有趣:它似乎是用第一个参数 a 调用的。 ,这大概是一个函数。看起来它可能会调用 bind在引擎盖下。当我要求控制台检查它时,我得到了这个:
> String(g.D)
"function(a,b,c){return a.call.apply(a.bind,arguments)}"
所以虽然这个过程有点复杂,但我们可以清楚地看到这确实发生了。

关于javascript - 为什么 function.toString() 输出 "[native code]",而登录到控制台直接显示函数的源代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68485652/

相关文章:

int - Kotlin是否有将数字格式化为英语序数的标准方法?

javascript - 向文本子字符串添加新元素

javascript - 如何保存焦点上最后一个元素的值

javascript - 如何用箭头移动 Canvas 中的对象?

javascript - Firebase:限制 child 对创建它的浏览器 session 的写访问权限

java - 在 Java/Eclipse 中推断变量类型,如 C#'s "var"

c# - asp.net中如何更改日期字符串的格式

java - 递归函数可以在函数的原始调用中更改变量吗?

function - awk 在重定向中出现函数调用错误

Java/包含多个 '.'运算符的语句