6.5 函数是一种对象
函数也是一种对象。从内部结构来看,它继承于 Function 对象。可以像下面这样通过 constructor 属性验证。
function hzh() {} // 函数的内容无关紧要,因此留空 console.log("使用constructor属性验证函数hzh:"); console.log(hzh.constructor);
[Running] node "e:\HMV\JavaScript\JavaScript.js" 使用constructor属性验证函数hzh: [Function: Function] [Done] exited with code=0 in 2.145 seconds
将匿名函数赋值给某个变量,与将 Function 对象的引用赋值给某个变量,在本质上是相同的,仅仅是表述方式的不同而已。在通常的语境中,函数的概念等价于 Function 对象的引用。因此,函数的声明与 Function 对象的生成也是等价的。
从形式上来看,代码清单 6.8 中例举的 4 种方式差异巨大,不过从整体上来看,这些代码的功能是类似的,都是先生成一个实体(即没有名字的对象),之后将其与引用了它的名称相结合。
代码清单 6.8 从整体上来看,都是生成了实体并赋予一个引用了该实体的名称。
var hzh = {}; var hzh = new hzhClass(); var hzh = function() {}; function hzh() {}
可以像下面这样,通过对 Function 函数进行构造函数调用,来生成一个 Function 对象。不过这种用法并不多见。
// 函数声明(Function对象的生成) var hzhSum = Function('a', 'b', 'return Number(a) + Number(b);'); // 最后一个参数是函数体。它之前的参数都是函数的形参。 // 函数的调用 console.log(hzhSum(3, 4));
[Running] node "e:\HMV\JavaScript\JavaScript.js" 7 [Done] exited with code=0 in 0.175 seconds
由于函数是一种对象,因此自然可以读写 Function 对象的属性。
function hzh() {} // 函数内部的内容对读写操作不会造成影响,因此在此使用了一个空函数 hzh.huangzihan = '黄子涵'; console.log('输出hzh对象的huangzihan属性:'); console.log(hzh.huangzihan);
[Running] node "e:\HMV\JavaScript\JavaScript.js" 输出hzh对象的huangzihan属性: 黄子涵 [Done] exited with code=0 in 0.199 seconds
如果对属性赋值以其他的函数,就相当于为该函数(对象)添加了方法。
function hzh() {} // 函数内部的内容对读写操作不会造成影响,因此在此使用了一个空函数 hzh.huangzihan = '黄子涵'; hzh.huangchunqin = function() { console.log('黄春钦是黄子涵的弟弟。'); } console.log("输出hzh对象的huangchunqin属性:"); console.log(hzh.huangchunqin); console.log(""); console.log("调用hzh对象的huangchunqin方法:"); console.log(hzh.huangchunqin());
[Running] node "e:\HMV\JavaScript\JavaScript.js" 输出hzh对象的huangchunqin属性: [Function] 调用hzh对象的huangchunqin方法: 黄春钦是黄子涵的弟弟。 undefined [Done] exited with code=0 in 0.201 seconds
在这种情况下,一个变量与其所引用的对象之间的关系可能有些复杂,不过只要记住 Function 对象含有一些可执行代码的这一事实,就不会有什么问题(图 6.2)。
图 6.2 变量 f 所引用的 Function 对象(Function 对象中含有引用了其他函数的变量)
函数名与调试的难易度
对象从本质上来说是不具有名称的。由于函数也是一种对象,所以 Function 对象也没有名称。从原则上来说这没有错,不过有必要再对此做一些补充说明。在通过函数声明语句以及匿名函数表达式对函数名进行指定时,在 Function 对象的内部储存了其表示名称。
在下面的代码中,hzh_name 的部分将作为 Function 对象的表示名称。
function hcq_name() { ... } // 函数声明语句 var hzh = function hcq_name() { ... } // 匿名函数表达式
“函数的表示名称”,使用这一名称为了与通常的函数名的概念相区分。
函数名是具有 Function 对象的引用的变量名。而“函数的表示名称”则是被储存于 Function 对象内部的名称。虽然无法直接通过“函数的表示名称”来调用函数,不过对于使用函数声明语句的情况,由于在 function 之后所写的名称就是其函数名,所以从表面上来看并没有区别。然而在内部,函数名与函数的表示名称是分别存在的。下面的代码没什么实际意义,不过可以对这一点进行验证。
function hcq() {} // 函数声明语句。由于内部的内容对调用操作不会造成影响,而在此使用了一个空函数 var hzh = hcq; // 这样一来就可以通过函数名 hzh 对其进行调用 hcq = null; // 将变量 hcq 的值置为 null console.log(hzh); // “函数的表示名”仍然为 hcq
[Running] node "e:\HMV\JavaScript\JavaScript.js" [Function: hcq] [Done] exited with code=0 in 0.177 seconds
在对 Function 对象进行 console.log() 等操作时会使用函数的表示名称。例如,在显示 constructor 属性所引用的 Function 对象时,所表示的名称即函数的表示名称。而在调试中显示调用栈时,函数的表示名称将发挥更大的作用。
在 JavaScript 程序设计中,与函数声明语句相比,使用匿名函数表达式的情况似乎越来越多。这时,常常会省略写在 function 之后的函数的表示名称。但因为在调试过程中函数的表示名称是非常有用的,所以还请对这一问题多加考虑。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?