当前位置: 首页 > java >正文

慢慢理解this

this 指向()=>{}  继承自父级作用域function(){}动态绑定(调用者)

代码1和代码1对照提现了,谁调用就在谁的作用域里找this指定的值

代码1:

const name = "Global Alice";const obj = {name: "Object Alice",greet: function () {console.log("this.name:", this.name); // 依赖 this 绑定console.log("name:", name); // 依赖作用域链(全局 name)}
};
const greetFunc = obj.greet;
greetFunc();
// 输出:
// this.name: undefined(this 指向全局,但全局 this.name 未定义)
// name: "Global Alice"(作用域链找到全局 name)

代码1对照

const name = "Global Alice";
const obj = {name: "Object Alice",greet: function () {console.log("this.name:", this.name); // 依赖 this 绑定console.log("name:", name); // 依赖作用域链(全局 name)}
};
obj.greet();
// 输出:
// this.name: Object Alice(this 指向 obj)
// name: Global Alice(作用域链找到全局 name)

要理解 “普通函数的 this 在调用时确定,取决于调用方式”,关键看函数被调用的那一刻,是 “谁” 在调用它。这两个示例的核心差异就在于 greet 函数的调用方式不同,导致 this 指向完全不同。

一、正确示例:obj.greet() —— 函数作为对象方法被调用

const obj = {name: 'Alice',greet: function() {console.log(`Hello, ${this.name}`);}
};obj.greet(); // 输出: Hello, Alice

  • 调用方式greet 函数作为 obj 的属性被调用(格式:对象.函数())。
  • this 指向规则:当函数作为对象的方法被调用时,this 指向该对象(即 . 前面的对象)。
  • 这里 greet 是 obj 的方法,调用时 obj 是 “调用者”,因此 this 指向 obj,自然能访问 obj.name(即 Alice

二、错误示例:greetFunc() —— 函数被单独调用(无调用者)

const obj = {name: 'Alice',greet: function() {console.log(`Hello, ${this.name}`);}
};const greetFunc = obj.greet; // 将函数本身赋值给变量
greetFunc(); // 输出: Hello, undefined

  • 调用方式greetFunc 是一个独立变量,直接调用(格式:函数()),没有任何 “调用者对象”。
  • this 指向规则:当函数独立调用(不依附于任何对象)时,this 指向全局对象(浏览器中是 window,Node 中是 global;严格模式下为 undefined)。
  • 这里 greetFunc 本质上是 greet 函数的 “引用”,调用时没有关联任何对象,因此 this 指向全局对象(而全局对象中没有 name 属性,所以输出 undefined)。

核心结论:this 指向由 “调用时的方式” 决定

两个示例中的 greet 是同一个函数,但调用方式不同,导致 this 指向完全不同:

  1. 当函数被对象 “持有” 并通过 对象.函数() 调用时,this 指向该对象。
  2. 当函数被单独取出(赋值给变量)并直接调用时,this 指向全局对象(或严格模式下的 undefined)。

这就是 “普通函数的 this 在调用时确定,取决于调用方式” 的本质:this 指向的不是函数定义时所在的对象,而是函数被调用时的 “上下文”(调用者)

代码2和代码2对照提现了()=>{}的this和谁调用无关,只和父级作用域有关

代码2:

const obj = {name: "Alice",greet: function() {const aaa = () => {console.log(this.name);  // 继承 greet 的 this(即 obj)};aaa();  // 直接调用箭头函数}
};obj.greet();  // 输出: "Alice"

代码2对照

const obj = {name: "Alice",greet: function() {const aaa = () => {console.log(this.name);  // 继承 greet 的 this(即 obj)};aaa();  // 直接调用箭头函数}
};obj.greet();  // 输出: "Alice"

代码3

const name = "全局名字";
// var name = "全局名字"const obj = {name: "Alice",greet: () => {console.log(this.name);}
};obj.greet();
// 输出 "全局名字"(箭头函数的 this 是定义时的父级 this,即全局作用域)

代码3对照

const name = "全局名字";const obj = {name: "Alice",greet: function () {console.log(this.name);}
};obj.greet();
// 输出 "Alice"(this 指向 obj)

这两段代码的核心区别在于 箭头函数和普通函数对 this 的处理方式不同,导致它们在相同的调用方式下访问不同的 name 属性。以下是详细的作用域分析和对比:

代码 1:箭头函数版本

const name = "全局名字";  // 全局变量(window.name)const obj = {name: "Alice",greet: () => {           // 箭头函数console.log(this.name);  // 继承全局作用域的 this}
};obj.greet();  // 输出: "全局名字"
作用域分析
  1. 全局作用域

    • 定义了变量 name,值为 "全局名字"
    • 全局作用域的 this 指向 window 对象(浏览器环境)。
  2. 对象 obj 的定义

    • 对象字面量 {...} 不创建新的作用域,因此 greet 箭头函数的外层作用域是全局作用域
  3. 箭头函数的 this

    • 箭头函数的 this 继承自外层作用域(全局作用域),即 window
    • this.name 实际上是 window.name,即 "全局名字"

代码 2:普通函数版本

const name = "全局名字";  // 全局变量(window.name)const obj = {name: "Alice",greet: function() {      // 普通函数console.log(this.name);  // 动态绑定 this}
};obj.greet();  // 输出: "Alice"
作用域分析
  1. 全局作用域

    • 同样定义了全局变量 name,值为 "全局名字"
  2. 对象 obj 的定义

    • greet 是一个普通函数,作为 obj 的方法存在。
  3. 普通函数的 this

    • 普通函数的 this 在调用时动态绑定,取决于调用方式。
    • 当 obj.greet() 被调用时,this 指向调用该方法的对象 obj
    • this.name 实际上是 obj.name,即 "Alice"

核心区别对比表

特性箭头函数版本普通函数版本
函数类型箭头函数普通函数
this 的绑定方式继承自外层作用域(定义时确定)动态绑定(调用时确定)
外层作用域全局作用域全局作用域
this 的指向全局对象 window调用该方法的对象 obj
this.name 的值window.name("全局名字")obj.name("Alice")

一句话总结

  • 箭头函数的 this 是静态的,继承自定义时的外层作用域(全局作用域),因此访问全局变量。
  • 普通函数的 this 是动态的,取决于调用方式(作为 obj 的方法调用时指向 obj),因此访问对象自身的属性。
http://www.xdnf.cn/news/15285.html

相关文章:

  • Dify离线安装包-集成全部插件、模板和依赖组件,方便安可内网使用
  • Matlab批量转换1km降水数据为tiff格式
  • 业务访问控制-ACL与包过滤
  • Qt窗口:QToolBar、QStatusBar、QDockWidget、QDialog
  • vue3 ref vs reactive值的修改
  • es里为什么node和shard不是一对一的关系
  • Git 使用笔记
  • 使用Starrocks替换Clickhouse的理由
  • SPSSPRO:数据分析市场SaaS挑战者的战略分析
  • 香港服务器Python自动化巡检脚本开发与邮件告警集成
  • 【Linux】线程机制深度实践:创建、等待、互斥与同步
  • 网络协议学习思维导图
  • python爬取新浪财经网站上行业板块股票信息的代码
  • java进阶(二)+学习笔记
  • 【算法】递归、搜索与回溯
  • Datawhale AI 夏令营2025科大讯飞AI大赛<夏令营:用AI做带货视频评论分析>
  • [Nagios Core] CGI接口 | 状态数据管理.dat | 性能优化
  • jenkins部署前端vue项目使用Docker+Jenkinsfile方式
  • 【星闪】Hi2821 | SDK开发入门,应用启动流程,创建自己的应用
  • 大模型聊天模板
  • 在人工智能自动化编程时代:AI驱动开发和传统软件开发的分析对比
  • AI 助力:如何批量提取 Word 表格字段并导出至 Excel
  • Infoblox NetMRI 远程命令执行漏洞复现(CVE-2025-32813)
  • C++值类别与移动语义
  • GraphRAG Docker化部署,接入本地Ollama完整技术指南:从零基础到生产部署的系统性知识体系
  • 动物世界一语乾坤韵芳华 人工智能应用大学毕业论文 -仙界AI——仙盟创梦IDE
  • 板凳-------Mysql cookbook学习 (十一--------9)
  • Typecho分类导航栏开发指南:从基础到高级实现
  • axios拦截器
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频摘要快速生成与检索优化(345)