JS筑基(二)-关于this指向

JavaScript 中的 this,到底指向谁?

你是否也写过这样的代码------

javascript 复制代码
const obj = {
  name: 'zhangsan',
  say() {
    console.log(this.name)
  }
}

const bar = obj.say
bar() // ?

大部分人第一次看到时会猜"zhangsan",结果打印出来却是 undefined。

为什么?因为 this 永远取决于函数"被调用的方式" ,而不是定义的位置。


一、this 是什么?

this 是在函数执行时 自动绑定的一个对象引用。

它的值取决于调用方式 ,而非函数定义的位置。

简单说:

"谁调用我,我就指向谁(除非你强制改变我)。"

  • 每一个函数都有自己的this,即使两个函数的指向相同,this本质上也不是同一个,this只在函数执行时产生
  • this在函数预编译时产生,每一个this都代表一个函数的执行

二、四种 this 绑定规则

1. 默认绑定 ------ 独立调用,指向 window(或 undefined)

当函数被独立调用 时,this 默认指向全局对象。

在浏览器中是 window,在严格模式下是 undefined。

scss 复制代码
function foo() {
  console.log(this)
}
foo() // window

2. 隐式绑定 ------ 谁调用,this 就指向谁

当函数作为对象的方法被调用时,this 会指向该对象。

javascript 复制代码
const person = {
  name: 'Tom',
  say() {
    console.log(this.name)
  }
}
person.say() // Tom

但是,如果"方法"脱离了对象独立执行,就会丢失隐式绑定,回到默认绑定规则:

csharp 复制代码
const fn = person.say
fn() // undefined(严格模式下)

⚠️ 注意闭包的情况:(什么是闭包?函数执行时,被定义并且被抛出)

javascript 复制代码
const obj = {
  name: 'Alice',
  outer() {
    function inner() {
      console.log(this.name)
    }
    inner()
  }
}
obj.outer() // undefined,因为 inner 独立执行

可以用箭头函数解决:

javascript 复制代码
const obj = {
  name: 'Alice',
  outer() {
    const inner = () => console.log(this.name)
    inner()
  }
}
obj.outer() // Alice

3. 显式绑定 ------ call / apply / bind

你可以手动指定 this:

scss 复制代码
function greet() {
  console.log(this.name)
}

const user = { name: 'Lucy' }

greet.call(user)  // Lucy
greet.apply(user) // Lucy
greet.bind(user)()// Lucy

区别:

  • call 和 apply 立即执行;
  • bind 返回一个新函数,之后执行;
  • apply 传参用数组形式。

如果传入的是原始类型(如字符串),this 会被转换为包装对象;

如果是 null 或 undefined,则退回默认绑定。


4. new 绑定 ------ 构造函数调用

当函数通过 new 调用时,会创建一个新对象,并将 this 绑定到该对象上。

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

底层过程相当于:

javascript 复制代码
function Person(name) {
  // var this = {}
  this.name = name
  // return this
}

如果构造函数显式返回对象,则返回该对象而不是 this:

javascript 复制代码
function Foo() {
  return { name: '自定义对象' }
}
console.log(new Foo()) // { name: '自定义对象' }

三、绑定优先级(最重要的判断规则)

绑定方式 示例 优先级 说明
new绑定 new Foo() 最高 创建实例时绑定
显式绑定 foo.call(obj) 高 手动指定
隐式绑定 obj.foo() 中 谁调用指向谁
默认绑定 foo() 低 非严格模式 → window

一句话记忆:

new > call/apply/bind > 对象调用 > 独立调用


四、箭头函数的特殊性

箭头函数没有自己的 this,它会继承外层作用域的 this 。

因此,所有四条绑定规则都对它无效。

javascript 复制代码
const obj = {
  name: 'Tom',
  say: () => console.log(this.name)
}
obj.say() // undefined(继承自全局作用域)

但如果在函数作用域内使用箭头函数,则可以捕获父作用域的 this:

javascript 复制代码
const obj = {
  name: 'Tom',
  outer() {
    const inner = () => console.log(this.name)
    inner()
  }
}
obj.outer() // Tom

五、如何快速判断 this 指向?

可以按这个顺序判断:

  1. 函数是否通过 new 调用?→ 指向实例;
  2. 是否通过 call / apply / bind 显式指定?→ 指向指定对象;
  3. 是否作为对象属性被调用?→ 指向该对象;
  4. 否则 → 默认绑定(window / undefined)。

六、总结

  • this 与函数定义无关,只与调用方式有关。
  • 四种绑定方式依次为:默认、隐式、显式、new。
  • 箭头函数没有自己的 this,会继承外层作用域。
  • 绑定优先级:new > 显式 > 隐式 > 默认。

📌 小贴士:闭包与 this 的区别

闭包让函数"记住变量的作用域";

this 决定函数"执行时的对象环境"。

两者常被混淆,但机制完全不同。


💡 写在最后

很多人初学时死记规则,不如换个角度思考:

this 不是"绑定函数"的机制,而是"绑定调用者"的机制。

只要你在执行前先问自己一句:

"这个函数是谁在调用?"

那你就永远不会搞错 this。


相关推荐
yume_sibai4 分钟前
04-Nginx部署实战完全指南(前端部署 + 后端代理 + 监控告警 + 故障排查)
运维·前端·nginx
data analyse 45615 分钟前
数据合规的同意记录怎么留存?
前端·人工智能·数据分析
linux_cfan20 分钟前
videojs v10 源代码系列解读:35 · HLS 解析器:multivariant 与 media playlist
前端·javascript·音视频
IT_陈寒22 分钟前
Redis键过期失效?这个坑我踩得明明白白
前端·人工智能·后端
web打印社区23 分钟前
汽修 / 4S 店:维修工单、结算单网页怎么静默出纸
开发语言·前端·javascript·chrome·ecmascript
liangshanbo121537 分钟前
Webpack的分包策略面试题
前端·webpack·node.js
ttwuai42 分钟前
Golang Web后台管理框架推荐:Gin、GoFrame与数据面板项目怎么分
前端·golang·gin
广州华水科技43 分钟前
北斗GNSS变形监测系统在水库安全监测中的应用与优势
前端
27669582921 小时前
youdao/有道翻译APP 算法协议分析
开发语言·前端·python·sign·youdao·有道翻译app算法·有道app协议请求