🚀 个人简介:某大型测绘遥感企业资深Webgis开发工程师,软件设计师(中级)、优快云优质创作者
💟 作 者:柳晓黑胡椒❣️
📝 专 栏:js燃烧吧!!!
🌈 若有帮助,还请关注 ➕ 点赞➕收藏,不行的话我再努努力💪💪💪
本文整理了一道经典的 JS 面试题及其解析,配合示例代码,你可以在实际项目中直接验证或二次封装,提升理解。
✨ 欢迎大家在评论区交流心得或提出建议,需要完整源码的,也可以私信我获取。
Background
继上一篇《原型与原型链|10 分钟读懂 JS 的面向对象核心》之后,
本篇是 「JS燃烧吧🔥」专栏 的第一弹。
我们这次来聊一道经典的面试题,几乎把 new、this、原型链和运算符优先级一锅端了。
我第一次看到这题时,脑子一团浆糊 🤯 ——
一边执行函数、一边改全局、一边又 new,还夹着隐式 this。
于是我花了点时间,把每一步的执行顺序都理了一遍,
想和大家一起彻底搞清楚这道“绕得明明白白”的 JS 题。
👉 如果这篇让你也瞬间通透,记得点个赞支持一下 ❤️
— JS燃烧吧 🔥 系列继续升温!
题目
function Foo(){
getName = function(){console.log(1)}
return this
}
Foo.getName = function(){console.log(2)}
Foo.prototype.getName = function(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){console.log(5)}
Foo.getName()// flag1
Foo().getName()// flag2
getName()// flag3
new Foo.getName()// flag4
new Foo().getName()// flag5
new new Foo().getName()// flag6
Output
| Flag | Code | Output |
|---|---|---|
| flag1 | Foo.getName() | 2 |
| flag2 | Foo().getName() | 1 |
| flag3 | getName() | 1 |
| flag4 | new Foo.getName() | 2 |
| flag5 | new Foo().getName() | 3 |
| flag6 | new new Foo().getName() | 3 |
function Foo(){
getName = function(){console.log(1)}
return this
}
Foo.getName = function(){console.log(2)}
Foo.prototype.getName = function(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){console.log(5)}
Foo.getName()//2 flag1
Foo().getName()//1 flag2
getName()// 1 flag3
new Foo.getName()//2 flag4
new Foo().getName()//3 flag5
new new Foo().getName()//3 flag6
Step-by-Step Analysis
flag1: Foo.getName() → 2
这里访问的是 Foo 构造函数的静态方法,也就是直接挂在 Foo 本身的函数,而不是实例上的方法。
执行流程:
1️⃣ 通过 Foo.getName() 调用,JS 直接找到构造函数的静态方法
2️⃣ 执行函数体内的 console.log(2)
✅ 输出:2
🎯 小贴士:静态方法不会挂在实例上,只能通过类名调用
flag2: Foo().getName() → 1
分两步理解:
1️⃣ 执行 Foo():
- 内部 getName = function(){console.log(1)} 会覆盖全局 getName
- 返回 this(浏览器环境下是 window)
2️⃣ 调用.getName(): - 相当于 window.getName()
- 执行
console.log(1)
✅ 输出:1
🎯 小贴士:没有 var/let/const`的赋值会污染全局变量,注意全局命名冲突
flag3: getName() → 1
全局的 getName 已被 Foo() 内部覆盖,执行 getName() → 打印 1
✅ 输出:1
🎯 小贴士:全局函数/变量会被覆盖,顺序执行很重要
flag4: new Foo.getName() → 2
优先级:
函数调用的优先级大于new(无参数列表)- 等价于 new (Foo.getName)()
💡 执行流程:
1️⃣ 找到 Foo.getName
2️⃣ 执行 new Foo.getName() → 调用构造函数打印 2
3️⃣ 返回一个空对象 {}(构造函数默认行为)
✅ 输出:2
🎯 小贴士:注意运算符优先级,带括号和不带括号结果可能不同
flag5: new Foo().getName() → 3
优先级: new(带参数列表)的优先级大于函数调用
执行过程:
1️⃣ new Foo() → 创建实例对象 {}
- 构造函数执行
- 返回对象实例,原型链指向 Foo.prototype
2️⃣ .getName() → 查找实例对象
- 对象自身没有 getName
- 沿着原型链找到 Foo.prototype.getName()
- 执行
console.log(3)
✅ 输出:3
🎯 小贴士:实例属性 > 原型属性 > 构造函数静态属性
flag6: new new Foo().getName() → 3
这里分三步,思路和上面一样,从优先级考虑,需要三步拆解:
1️⃣ new Foo() → 创建实例 {}
2️⃣ .getName → 拿到原型上的函数 Foo.prototype.getName
3️⃣ new (Foo.prototype.getName)() → 执行构造函数打印 3
✅ 输出:3
🎯 小贴士:new 可以连续嵌套执行,但要注意优先级和括号

Takeaways
- 函数声明与变量提升会影响
getName的最终值 - this 指向在普通函数与构造函数中差别大
- 全局污染:无
var/let/const会改全局对象 - 原型链查找顺序:实例 → 原型 → 构造函数
- new 的执行规则与优先级:带参数
new Fn()优先级高于函数调用;无参数new Fn稍低 - 阅读技巧:遇到复杂链式调用时,可按
执行顺序 + 优先级表拆解
JS new、this与原型链解析

被折叠的 条评论
为什么被折叠?



