JS燃烧吧:new、this 与原型链魔法题

JS new、this与原型链解析

🚀 个人简介:某大型测绘遥感企业资深Webgis开发工程师,软件设计师(中级)、优快云优质创作者
💟 作 者:柳晓黑胡椒❣️
📝 专 栏:js燃烧吧!!!
🌈 若有帮助,还请关注点赞收藏,不行的话我再努努力💪💪💪


本文整理了一道经典的 JS 面试题及其解析,配合示例代码,你可以在实际项目中直接验证或二次封装,提升理解。
✨ 欢迎大家在评论区交流心得或提出建议,需要完整源码的,也可以私信我获取。

Background

继上一篇《原型与原型链|10 分钟读懂 JS 的面向对象核心》之后,
本篇是 「JS燃烧吧🔥」专栏 的第一弹。
我们这次来聊一道经典的面试题,几乎把 newthis原型链运算符优先级一锅端了。
我第一次看到这题时,脑子一团浆糊 🤯 ——
一边执行函数、一边改全局、一边又 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

FlagCodeOutput
flag1Foo.getName()2
flag2Foo().getName()1
flag3getName()1
flag4new Foo.getName()2
flag5new Foo().getName()3
flag6new 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 稍低
  • 阅读技巧:遇到复杂链式调用时,可按执行顺序 + 优先级表拆解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳晓黑胡椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值