为何可在函数声明前为其属性赋值?相关代码执行原理解析
嘿,这两个问题其实都和JavaScript的**变量提升(Hoisting)**机制密切相关,尤其是函数声明的特殊提升特性,咱们一个个拆解清楚:
问题1:为何可以在函数声明前为其属性赋值?
JavaScript里的函数声明会被完整提升到当前作用域的最顶部——换句话说,在代码正式执行前的"编译阶段",JS引擎就已经创建好了这个函数对象,并且把对应的函数标识符(比如例子里的uniqueInteger)指向了这个对象,哪怕你的函数声明写在代码的后面。
所以当你在函数声明前写uniqueInteger.count = 0的时候,uniqueInteger已经是一个有效的函数对象了,自然可以给它添加属性。这就好比你先拿到了一个空盒子(函数对象),先在盒子上贴个标签(属性),之后再往盒子里装东西(函数体代码),完全不冲突。
问题2:为何未声明uniqueInteger时赋值属性代码仍能正常执行?
这里其实是个小误解——uniqueInteger其实已经被"声明"了,只是它的声明被提升到了代码的最前面。
咱们把你的代码按照JS引擎实际的执行顺序重新梳理一下,真实的执行流程是这样的:
// 编译阶段:函数声明被提升到作用域顶部 function uniqueInteger() { return uniqueInteger.count++; } // 执行第一行赋值代码 uniqueInteger.count = 0; // 调用函数并输出 console.log(uniqueInteger()); // 输出 0 console.log(uniqueInteger()); // 输出 1
因为函数声明的提升优先级比普通变量声明还要高,所以在执行uniqueInteger.count = 0的时候,uniqueInteger已经是一个存在的函数对象了,根本不会出现"未声明"的情况。这也是为什么代码能正常运行,最后输出0和1。
补充个小知识点:如果这里的uniqueInteger是用var或者let声明的变量(而非函数声明),情况就完全不同了——var声明的变量会被提升但初始化为undefined,这时候给undefined添加属性会直接报错;let则处于暂时性死区,直接访问也会报错。但这里是函数声明,所以完全没问题。
内容的提问来源于stack exchange,提问作者DarkSun

