普通视图

发现新文章,点击刷新页面。
昨天以前首页

萌新小白基础理解篇之 this 关键字

作者 biubiubiu_LYQ
2026年5月27日 18:35

前言

  早在我们前几篇文章中,就有出现过 this ,但是我们一直没有详细解释 this 是什么,this 可以出现在哪,this 的用法又是如何?那这篇文章我们一起来看看吧!

一、为什么要有this?

  this 是 js 中的一个关键字,它提供了一种更优雅的方式隐式的传递一个对象的引用,可以让代码更简洁易于复用,js 关键字是内置好的,拥有特殊语法含义的词,不能作为变量名,函数名,还有if,else,for等等关键字。我们来看一段代码感受一下。

 function identify(context) {
   return context.name.toUpperCase()  //.toUpperCase()  让小写全转化为大写 
 }

 function speek(context) {
   var greeting = 'hello, I am ' + identify(context)
   console.log(greeting);
 }

 var me = {
   name: 'tom'
 }

 speek(me)  

  当代码运行到14行时带来speek()函数的调用,把me作为实参传进去,此时运行speek()函数又带来了identify() 的调用,将me作为实参传进去,返回得到大写的 TOM ,console.log(greeting)得到 hello,I am TOM。

image.png

  如果用 this 我们可以怎么写

function identify() {
  return this.name.toUpperCase()
}

function speek() {
  var greeting = 'hello, I am ' + identify.call(this)
  console.log(greeting);
}

var me = {
  name: 'tom'
}

speek.call(me)

  我们可以看到,上述结果是相同的,函数 speek 和 identify 不再接收 context 参数。

  • 使用 this 关键字直接访问调用上下文中的属性(如 this.name)。
  • 调用时,通过 .call(me) 显式绑定 this 指向目标对象。下文会详细解释.call()用法
  • 逻辑链条变为:对象 → 绑定为 this → 函数内部直接通过 this 访问

  它提供了一种更优雅的方式隐式的传递一个对象的引用,可以让代码更简洁易于复用。

image.png

二、this 可以出现在哪?

  • 1.全局 (this === window
  • 2.函数体内

  理论上,this 可以出现在任何地方,如果出现在全局,那么 统一代指 的是window,所以我们主要区分函数体内的 this 代指的是哪个,this 用在不同的地方,代指的内容是不一样的。

this 可以出现在块级作用域但是毫无意义

三、 this的绑定规则

1.默认绑定 --- 当函数独立调用时,函数中的 this 指向 window
var a = 1   //  ===window:{a:1}  等于往window里面增加了 a为1 

function foo(){
    console.log(this.a)  // 1
}

function bar () {
    var a = 2
    foo() //独立调用
}

bar()

   this 如果出现在全局,那么它代指 window , 此时 this 出现在foo函数内,但是这个foo函数是被独立调用的,那么此时 this 依旧指向 windowconsole.log(this.a) 为 1,什么叫独立调用呢? 独立调用 = 函数名直接加括号执行,没有任何对象或上下文“牵着”它。

2.隐式绑定 --- 当一个函数被一个上下文对象所拥有并被该对象调用,那么函数中的 this 指向该对象
var a = 1   //  ===window:{a:1}  等于往window里面增加了 a为1 

function foo(){
    console.log(this.a)   //3
}

function bar () {
    var a = 2
    foo() //独立调用
}

bar()

var test = {
    a : 3,
    foo :foo  //引用函数
}

test.foo()  //隐式绑定

  我们可以看到 前面的 foo() 就是单独的函数名+括号的形式, 后面的为 test.foo() ,打个比方,就像你一个人逛街和你女朋友牵着你逛街的区别,你一个人逛街就叫独立调用,有女朋友牵着就不叫独立调用,此处我们称之为隐式绑定,而此时 this 指向的对象 就是 test ,所以此时 console.log(this.a) 为3

3.隐式丢失 --- 当一个函数被多层对象调用,函数的 this 指向最近的对象
function foo(){
    console.log(this.a)
}
var obj = {
    a:1, 
    foo : foo   //key :value  ,key 的名字可以随便取, 但 value 不可以随便
}
var oo = {
    a : 2,
    foo : obj
}

oo.foo.foo()  //this 指向 obj

  我们来捋一捋这个代码的逻辑,v8运行这段代码,运行到13行前,知道有一个 foo函数 ,有一个obj 对象,一个 oo 对象,当运行到13行时,有函数的调用,才开始读取它们的内容,那代码是从左往右执行,先读取 oo.foo ,那v8就要去oo里面找这个 foo 是什么,我们可以看到此时的 foo 值为 obj 对象,那就相当于 obj.foo(), 在去obj中 找 foo 是什么,此时 foo 的值 为foo 函数 ,然后() 开始foo函数的调用,所以相当于是 obj 调用了这个函数,此时 this 指向 obj ,也即当一个函数被多层对象调用,函数的 this 指向最近的对象。

4.显示绑定 --- 强行''掰弯'' this 指向一个对象 (三种方法)
  • fn.call(obj, x, y)

  • fn.apply(obj, [x,y])

  • fn.bind(obj, x, y)()

function foo(x,y){
    console.log(this.a, x+y)
}

var A = {
    a : 1
}

foo() //独立调用 指向 window
foo.call(A,1,2)  //this 指向A  传递参数 1,2
foo.apply(A,[2,3])  // this 指向A 传入参数2,3 
foo.bind(A,1,2)() //this 指向A,传入参数1,2 

.call( obj, x, y) : 让 this 强行指向 A,可以逐个传递参数 (较为零散的方式传递参数)

.apply( obj, [x,y] ) : 让 this 强行指向 A,以数组的模式逐个传递参数 (较为集中的方式传递参数)

.bind( obj, x, y)() : 让 this 强行指向 A,但是执行完后一定会返回一个函数出来,并且要把它触发掉,也是零散的传递参数,也可以 const bar 来接收 返回的函数 再调用触发,可以分开传参

const bar = foo.bind(obj,x,y)   const bar = foo.bind (obj,x)   const bar = foo.bind (obj) 
bar()                            bar(y)                        bar(x,y)
5.new 绑定 --- new 的原理会导致函数的 this 指向实例对象
function Person(){
    // var obj = {}      //1
    //Person.call(obj)   //2
    this.name = '杰哥'    //3   等同于  obj.name = '杰哥'
    // obj.__proto__ = Person.prototype    //4
    //return obj         //5
}

const p = new Person()  //此时的 p = obj
console.log(p)   // {name : 杰哥}

  我们在万物皆对象那篇文章中有讲到过 new 的工作原理,但当时并没有详细解释 this 所以表述其实并不准确,new 的具体工作原理应该是这样

  • 创建一个空对象 即 var obj = {}

  • 让函数体的 this 强行指向 实例对象 即 Person.call(obj)

  • 运行函数内的代码逻辑

  • 让对象的原型等于函数的原型 即 obj.proto = Person.prototype

  • 返回这个对象 即 return obj

四、箭头函数

  箭头函数没有 this 这个概念,写在箭头函数中的 this,也是它外层那个非箭头函数的

var bar = function(){     //函数表达式

}
bar()

var baz = (x,y) => {     //函数表达式
   
}

  如果不用到 this ,两种写法都是可以的,但如果用到 this 那我们需要注意一下了

function foo(){
    var fn = () =>{   //箭头函数没有 this 这个概念
        this.a = 2
    }
    fn()
}

var obj = {
    a : 1,
    bar:foo
}
obj.bar()
console.log(obj)

  由于箭头函数没有 this 这个概念,写在箭头函数中的 this,也是它外层那个非箭头函数的,所以此时 this 是 foo的 ,而foo是通过obj.bar()调用的,所以 foo 的 this 指向 obj 对象,console.log(obj) 得到 { a : 1, bar : foo }

image.png

箭头函数不可以被new调用 (new的第二步无法执行,用了就会报错)

(如有补充,请大佬指点)

3fd2900e2e696b2fa8e8cedf528d1195.jpg

❌
❌