函数的方法2
约 674 字大约 2 分钟
2026-03-31
想一想,下面的代码在非严格模式下执行结果是什么?
JS code example
console
Click the run button to execute the code ...
在代码执行之前,先进入执行上下文阶段:确定给this 指向、创建词法环境、变量环境、处理声明提升等。 因此上面代码的各个声明先被处理为:
// Foo 函数提升
function Foo() { ... }
// 函数声明覆盖同名变量声明
function getName() { console.log(5) } // 先提升
// 变量声明提升(赋值不提升)
var getName; // 声明提升,但被函数声明覆盖下面开始执行:
// 给 Foo 添加静态方法
Foo.getName = function() { console.log(2) };
// 给 Foo 原型添加实例方法
Foo.prototype.getName = function() { console.log(3) };
// 变量赋值执行(此时才真正赋值!)
var getName = function() { console.log(4) };
// 全局 getName 被重新赋值为输出 4 的函数然后进入我们函数的执行:
Foo.getName()
// 直接访问 Foo 函数的静态属性
Foo.getName // → function(){ console.log(2) }getName()
// 访问全局变量 getName,此时已被赋值为输出4的函数
getName // → function(){ console.log(4) }Foo().getName()
// 分步执行:
// 执行 Foo()
function Foo() {
// 非在非严格模式下,给未声明的变量赋值会自动创建隐式全局变量
getName = function() { console.log(1) }; // 创建隐式全局变量,修改了全局 getName
return this; // this = window
}
// Foo() 返回 window,所以:
window.getName() // → 输出 1
// 副作用:全局 getName 被永久修改为输出 1 的函数!getName()
// 由于上一步创建了隐式全局变量,全局 getName 已变成输出 1 的函数
getName() // → function(){ console.log(1) }new Foo.getName()
// 运算符优先级:. 高于 new(无参数列表时)
// 解析为:new (Foo.getName)()
new (function(){ console.log(2) })()
// 执行函数体,输出 2
// new 创建新对象(但函数无逻辑,返回空对象)new Foo().getName()
// 解析顺序:(new Foo()).getName()
// new Foo() 创建实例
// - Foo 返回 this(实例对象),new 会忽略原始值返回,返回新实例
// - 实例的 __proto__ → Foo.prototype
// 实例调用 .getName()
// - 实例自身无 getName,沿原型链查找
// - Foo.prototype.getName → function(){ console.log(3) }
new Foo().getName() // → 输出 3new new Foo().getName()
// 复杂表达式,按优先级解析:NEW ((new Foo()).getName())()
// 最内层:new Foo() → 创建实例
// 实例.getName → 从原型链找到 function(){ console.log(3) }
// 外层 new 调用这个方法:new (function(){ console.log(3) })()
// 执行函数体,输出 3