今天我又被JavaScript的this绑架了!🚨

学习JS的一天:早上被变量提升搞懵,中午被this指向气哭,晚上被闭包和原型链折磨得睡不着觉。

今天在探索JavaScript的奇妙(诡异)世界时,我发现函数声明和this指向简直就像薛定谔的猫------你不执行代码永远不知道会发生什么。下面是我的血泪史总结,附带大量代码实验和灵魂图解!

🔥 第一章:函数名的"防篡改装甲"

情况一

在以下代码中,我发现函数名在函数体内居然是个"只读VIP":

javascript 复制代码
function b() {
    b = 20 // 试图篡位?门都没有!
    console.log(b) // 输出函数本体而非20
}
b() // 输出:[Function: b]

原理揭秘

  1. 函数声明会在当前作用域创建同名的不可写绑定
  2. 在严格模式下直接报错:TypeError: Assignment to constant variable
  3. 函数表达式中的命名函数同样受此保护
  4. 非严格模式下,会在函数题内部创建一个只读的局部变量,会忽略重新赋值

情况二

我们再来看以下代码:

js 复制代码
var b = 10;
 function b() { // 函数声明
    b = 20 // 不生效的
     console.log(b)
 }
 b()//TypeError: b is not a function,b是一个变量不是函数,不能被调用
 
 

为什么会输出b不是一个函数呢?

var 和 函数声明都会进行变量提升,函数是第一等对象,会提升至最顶部其实就是变成了下面的代码

js 复制代码
 function b() { // 函数声明
  b = 20 // 不生效的
   console.log(b)
}
var b//重新赋值 b变成一个变量,而不是函数
b=10

所以输出TypeError: b is not a function,b是一个变量不是函数,不能被调用

情况三

具名函数表达式

js 复制代码
var b = 10;
const func = function b() { // 函数表达式
    b = 20 // 不生效的
    console.log(b)
}
func()// [Function: b]

原理:

情况一是类似的函数内部会产生一个局部变量b,是只读的,在非严格模式下,在函数体内容重新赋值会被忽略

在严格模式下,这是一种潜在的错误,会抛出错误,TypeError: Assignment to constant variable

情况四

js 复制代码
var b = 10;
(function b() {
    b = 20 // 不生效的
    console.log(b)
})()

这是一个立即执行函数,和情况二就就不同了,虽然函数会被提升,但是其直接立即执行了,所以不会等到下面的对b赋值为一个变量,所以不会显示b不是一个函数,而是和情况一相同,会输出函数b

在严格模式下,同样的,这是一个潜在的错误,会直接抛出错误TypeError: Assignment to constant variable

情况五

匿名函数表达式

js 复制代码
var b=10
const func = function () { // 函数表达式
    b = 20 // 不生效的
    console.log(b)
}

由于是匿名函数,在函数内部是没有具体变量名来访问的,suoyb就指向外面声明的b,会修改b为20,所以最后输出的是20

✅ 总结对比表:

写法 是否是 IIFE 是否具名 是否可修改 b = 20 输出 严格模式输出
var b = 10 (function b() { b = 20; console.log(b); })() ✅ 是 ✅ 具名 ❌ 不可修改(严格模式) 函数自身 报错:TypeError: Assignment to constant variable
var b = 10 function b() { b = 20; console.log(b); } ❌ 否 ✅ 具名 ✅ 可修改(函数名不遮蔽) b is not a function 报错:b is not a function
var b = 10 var myFunc = function b() { b = 20; console.log(b); } ❌ 否 ✅ 具名 ❌ 不可修改 函数自身 报错:TypeError: Assignment to constant variable
var b = 10 var myFunc = function () { b = 20; console.log(b); } ❌ 否 ❌ 不具名 ✅ 可修改 20 20
function b() { b = 20; console.log(b); } ❌ 否 ✅ 具名 ✅ 可修改 20 20

🌍 第二章:全局变量的"双面人生"

2.html2.js中,我发现了全局变量的精分现场:

2.html 复制代码
<script>
    "use strict";
    var a = 1;
    console.log(window.a); // 1 → 挂载到window
    let aa = 1;
    console.log(window.aa); // undefined → 拒绝污染window
</script>
2.js 复制代码
var a = 1;
// console.log(window.a);// ReferenceError: window is not defined 因为在后端运行,没有window
console.log(global.a); // global 是 node 里面的顶层对象

跨环境差异表

声明方式 浏览器环境 Node环境 是否污染顶层对象
var 挂载到window 不挂载到global
let/const 不挂载 不挂载
函数声明 挂载 挂载

💡 冷知识:ES6的let/const变量存在于"Script作用域"这个隐形结界中,完美避开了顶层对象污染问题!

🎯 第三章:this指向的"川剧变脸"

3.html6.html中,我见证了this的七十二变:

场景1:普通函数调用(3.html

3.html 复制代码
var name = '张三';
function func() {
    console.log(this.name); // 张三(非严格模式)
}
func(); // 等价于window.func()

场景2:对象方法调用(4.html

4.html 复制代码
var a = {
    name: '娄老板',
    fn: function() {
        console.log(this.name); // '娄老板'
    }
}
a.fn(); // this秒变对象

场景3:构造函数调用(5.html

5.html 复制代码
function Person(name) {
    this.name = name; // this指向新生的婴儿
}
const p = new Person('labubu'); 

场景4:DOM事件处理(6.html

6.html 复制代码
input.addEventListener('keydown', function() {
    console.log(this); // 触发事件的input元素
});

场景5:严格模式大乱斗(4.html

4.html 复制代码
"use strict";
var b = a.fn;
b(); // 普通调用 → this变成undefined(非严格模式才是window)

⚠️ 血泪教训 :this的值取决于函数被调用的方式,而不是定义的位置!它就像婚礼上的捧花------谁接到就是谁的。

🏹 第四章:箭头函数的"定海神针"

7.html中,箭头函数用this的稳定性治愈了我的精神内耗:

7.html 复制代码
var a = {
    name: 'Tom',
    func2: function() {
        setTimeout(() => {
            console.log(this.name); // 'Tom'(锁定父级this) ye就是对象a
        }, 1000)
    }
}
a.func2();

传统函数 vs 箭头函数

💎 核心知识总结(含泪整理版)

  1. 函数名保护机制

    • 函数声明/表达式的名称在函数体内不可重写
    • 严格模式直接报错,非严格模式静默失败
  2. 全局变量管理

    ini 复制代码
    // 污染顶层对象 ❌
    var legacyVar = 1; 
    
    // 清洁能源 ✅
    let modernLet = 2; 
    const MODERN_CONST = 3;
  3. this指向五大门派

    调用方式 this指向 典型场景
    普通调用 window/undefined func()
    对象方法调用 调用对象 obj.method()
    构造函数调用 新创建实例 new Person()
    DOM事件处理 触发元素 elem.onclick
    箭头函数 定义时的外层this () => {...}
  4. 箭头函数三大铁律

    • 没有自己的this、arguments、super
    • 不能作为构造函数使用
    • 没有prototype属性

🌈 后记:从被绑架到掌控全局

今天在JavaScript的迷宫中探险时,我经历了从"这代码见鬼了吧?"到"原来如此!"的顿悟时刻。记住这些黄金法则:

函数名是只读贵族 👑 → 别试图在函数内部篡位
var是污染源 ☣️ → let/const才是环保卫士
this是墙头草 🌾 → 谁调用它就跟谁走
箭头函数是定海神针 🏹 → 定义时锁定this结界

最后送上我的灵魂感悟:
"学习JavaScript就像和傲娇猫主子相处------你以为你在控制它,其实是它在训练你。" 😼

(本篇笔记由被this折磨了8小时的客户端记者为您发回现场报道)

相关推荐
a别念m1 分钟前
webpack基础与进阶
前端·webpack·node.js
芭拉拉小魔仙15 分钟前
【Vue3/Typescript】从零开始搭建H5移动端项目
前端·vue.js·typescript·vant
axinawang16 分钟前
通过RedisCacheManager自定义缓存序列化(适用通过注解缓存数据)
前端·spring·bootstrap
白露与泡影17 分钟前
Java面试避坑指南:牛客网最新高频考点+答案详解
java·开发语言·面试
前端南玖26 分钟前
Vue3响应式核心:ref vs reactive深度对比
前端·javascript·vue.js
哔哩哔哩技术34 分钟前
B站在KMP跨平台的业务实践之路
前端
微笑边缘的金元宝34 分钟前
svg实现3环进度图,可动态调节进度数值,(vue)
前端·javascript·vue.js·svg
程序猿小D38 分钟前
第28节 Node.js 文件系统
服务器·前端·javascript·vscode·node.js·编辑器·vim
Trae首席推荐官40 分钟前
字节跳动技术副总裁洪定坤:TRAE 想做 AI Development
前端·人工智能·trae
小妖66641 分钟前
uni-app bitmap.load() 返回 code=-100
前端·javascript·uni-app