跳到主要内容

函数属性与命名自省

length 与 name 如何反映函数形态?​

  • function.length: 形参数量 (不含剩余参数与带默认值之后的参数);
  • function.name: 函数名, 详见 函数名与提升;

函数的 name 还能从哪里推断出来?​

  • 语义: 规范称"上下文名称" (contextual name), 无显式名字时按上下文推断, 基础规则见 函数名与提升;
  • 推断来源: 变量赋值取变量名, 默认参数值取形参名, 对象方法取属性名; 数组元素等无处取名的位置则得到空字符串;
let sayHi = function () {};
const user = { sayBye: function () {} }; // sayBye.name === "sayBye"

函数的 length 如何用于自省?​

  • 语义: 返回形参个数, 剩余参数不计入, 见上文"length 与 name 如何反映函数形态?";
  • 用途: 让"接收函数的函数"按 handler.length 决定调用方式, 属于按参数形态分派的多态手法; 如 ask(question, ...handlers) 中 length === 0 的处理器只在肯定回答时调用, 有参处理器两种回答都调用;
function many(a, b, ...more) {}
many.length; // 2

函数能挂自定义属性吗?与闭包如何取舍?​

  • 可以: 函数是对象, 属性可读可写, 常用于在函数自身上保存状态; 但函数属性与函数体内的局部变量互不影响, 是两个平行世界;
function counter() {
return counter.count++;
}
counter.count = 0;
counter.count = 10; // 状态可被外部改写
counter(); // 10
  • 取舍: 闭包变量外部不可见, 只有内层函数能改; 函数属性外部可读写, 便于观察或重置;
  • 生态用法: 库把辅助函数挂在主函数上 (如 _、$), 只占一个全局名字;

NFE 命名函数表达式解决了什么问题?​

  • 定义: 带名字的函数表达式 function func(who){}, 仍是表达式而非声明;
  • 特性: 名字可在函数内部自引用, 对外不可见;
  • 价值: 递归若用外层变量名, 外部改赋或置空后递归即崩; 内部名由规范保证始终指向当前函数;
  • 限制: 函数声明没有内部名语法, 需要可靠自引用时应改写成 NFE;
let sayHi = function func(who) {
if (!who) return func("Guest"); // 稳定自引用
};
let welcome = sayHi;
sayHi = null;
welcome(); // 仍能递归

new Function 创建函数有什么特点?​

  • new Function(...) 由字符串创建函数, 作用域与风险同 eval, 详见 Math 与 Global;
  • name: 未命名时其 name 为 "anonymous", 见 函数名与提升;