this 到底指向谁?严格模式和作用域那些坑全讲明白了

理解运行机制,比掌握语法更重要。

引言

JavaScript 作为前端开发的核心语言,看似简单,实则隐藏着不少运行时的"小机关"。

你可能遇到过这些困惑:

  • varlet 到底差在哪?
  • this 到底指向谁?
  • "use strict" 到底严格在哪?

这篇文章就用 例子 + 原理,带你搞懂 JS 的运行底层逻辑,从变量声明、作用域,到 this 指向和严格模式。


1️⃣ 变量声明:varletconst 真不同

var:老派选手,默认上全局

js 复制代码
var a = 1;
console.log(window.a); // 1

在浏览器环境中,var 声明的变量会挂在 window 对象上,相当于 window.a = 1

这就意味着,所有页面代码都可以访问和修改这个变量,容易产生污染或冲突。

let / const:ES6 新时代的安全声明

js 复制代码
let b = 2;
console.log(window.b); // undefined

使用 letconst 声明的变量,不会挂到全局对象上,而是局部存在于当前块级作用域中。

此外:

  • let 支持重新赋值,const 不支持;
  • 它们都有"暂时性死区"(TDZ):在声明前访问会报错。

2️⃣ 严格模式:让 JS 不再"睁一只眼闭一只眼"

启用方式:

js 复制代码
"use strict";

在严格模式下:

  • 禁止未声明变量直接赋值;
  • 禁止删除变量名;
  • this 在普通函数中不再默认指向 window,而是 undefined
  • 命名函数表达式的名字是只读的;

看看这个例子👇:

js 复制代码
"use strict";
(function b() {
  var b = 20;
  console.log(b); // 20,而不是函数名
})();

你可能听说「函数名在严格模式下是只读的」,于是以为变量无法覆盖。但实际上 var b = 20 是合法的,它创建了一个新的局部变量,屏蔽了函数名变量 b ,所以输出的是 20

真正只读限制的例子如下:

js 复制代码
"use strict";
(function b() {
  b = 123; // ❌ TypeError:不能给函数名 b 重新赋值
})();

3️⃣ this:不是写在哪,而是怎么调用

this 的值,总是函数执行时决定的,而不是写代码的位置。

来看几个经典场景:

✅ 作为对象方法调用:

js 复制代码
var obj = {
  name: '娄老板',
  say() {
    console.log(this.name);
  }
};
obj.say(); // 输出:娄老板

❌ 普通函数调用:

js 复制代码
var fn = obj.say;
fn(); // 非严格模式下输出:window.name(如果有);严格模式下为 undefined

✅ 构造函数中,this 指向实例对象:

js 复制代码
function Person(name) {
  this.name = name;
}
const p = new Person('labula');
console.log(p.name); // labula

⚠️ 如果忘记 new

js 复制代码
const p2 = Person('小明');
console.log(window.name); // 被污染了!this 指向 window

4️⃣ window 与全局变量:曾经的设计,现在的"坑"

早期 JS 设计时,所有全局变量都挂在 window 上,是为了方便浏览器访问。

这也让下面的行为成立:

js 复制代码
var user = '张三';
console.log(window.user); // 张三

但是这会让全局空间变得非常容易污染。

所以 letconst 就成为更好的选择,它们不会绑定到全局对象:

js 复制代码
let score = 99;
console.log(window.score); // undefined

总结回顾

概念 特性/行为
var 声明 会挂到 window,作用域为函数级
let / const 块级作用域,不挂 window,有 TDZ
this 运行时决定,严格模式下默认是 undefined
严格模式 更安全,限制更多,调试更容易

写在最后

JavaScript 是一门看起来随和,实则套路很多的语言。this 指向、作用域规则、严格模式这些东西不难,但很容易忽略。

它们藏在一些看似"正常"的代码背后,很多 bug 其实都是对这些机制理解不到位导致的。

希望这篇文章能帮你把一些模糊地带捋清楚。真正理解它们,写 JS 才会越来越稳。


如果你觉得有帮助,欢迎点赞、收藏或分享这篇文章!

相关推荐
2601_94980959几秒前
flutter_for_openharmony家庭相册app实战+隐私设置实现
android·javascript·flutter
2601_949593652 分钟前
React Native 鸿蒙跨平台开发:LinearGradient 渐变动画效果
javascript·react native·react.js
黄筱筱筱筱筱筱筱3 分钟前
7.适合新手小白学习Python的异常处理(Exception)
java·前端·数据库·python
qq_177767374 分钟前
React Native鸿蒙跨平台音乐播放器涉及实时进度更新、播放控制、列表交互、状态管理等核心技术点
javascript·react native·react.js·ecmascript·交互·harmonyos
2501_920931708 分钟前
React Native鸿蒙跨平台实现了简单的商品图片轮播功能,为用户提供了直观的商品图片浏览体验,帮助用户全面了解商品外观
javascript·react native·react.js·ecmascript·harmonyos
Yeats_Liao10 分钟前
微调决策树:何时使用Prompt Engineering,何时选择Fine-tuning?
前端·人工智能·深度学习·算法·决策树·机器学习·prompt
晚霞的不甘11 分钟前
Flutter for OpenHarmony 实现 iOS 风格科学计算器:从 UI 到表达式求值的完整解析
前端·flutter·ui·ios·前端框架·交互
陈希瑞14 分钟前
OpenClaw Chrome扩展使用教程 - 浏览器中继控制
前端·chrome
雨季66618 分钟前
Flutter 三端应用实战:OpenHarmony “呼吸灯”——在焦虑时代守护每一次呼吸的数字禅修
开发语言·前端·flutter·ui·交互
切糕师学AI19 分钟前
Vue 中如何修改地址栏参数并重新加载?
前端·javascript·vue.js