细说JavaScript中的this指向与绑定规则

作者:函数茶馆

时间:2026-10-30

浏览:206

本文深入解析JavaScript中this的指向机制,详细阐述默认绑定、隐式绑定、显示绑定及new绑定的4条核心规则。通过代码示例说明this在运行时的动态绑定特性,分析绑定优先级,并探讨null/undefined绑定、软绑定及箭头函数无this的特殊情况,帮助开发者准确掌握this行为。

文章目录

this的指向

在浏览器环境中,全局作用域下的this通常指向window对象,且这一行为不受严格模式影响。但在实际开发中,this更多出现在函数内部。每当函数被调用时,JavaScript引擎会创建一个新的函数执行上下文,其中包含作用域链、活动对象(AO)以及当前函数的this绑定值。参考以下代码:

function foo() {
  console.log(this)
}
foo()//window
var obj = {
  name: 'why',
  foo: foo
}
obj.foo()//obj
foo.apply("abc")//String{'abc'}

上述代码定义了一个函数foo,用于输出调用时的this值。执行结果显示,分别指向window、obj以及String包装对象{'abc'}。由此可以得出以下结论:

  • 函数在调用时,JavaScript引擎会默认给this绑定一个值;
  • this的绑定结果与函数定义的位置(即编写代码时的位置)无关;
  • this的绑定结果取决于函数的调用方式以及调用发生的位置;
  • this是在代码运行时动态绑定的,而非在编译阶段固定。

判断this绑定的4条规则

规则1:默认绑定

当进行独立函数调用时,this始终绑定到window对象(非严格模式)或undefined(严格模式)。示例如下:

function foo() {
   console.log(this)
}
function foo2() {
   foo()
}
var obj = {
  name: "xiaomin",
  foo: function() {
    console.log(this)
  }
}
foo()//window
foo2()//window
var bar = obj.foo
bar()//window

规则2:隐式绑定

若函数通过某个对象属性发起调用,则this隐式绑定到该对象上。具体表现为:

var obj1 = {
  name: "obj1",
  foo: function () {
    console.log(this);
  },
};
var obj2 = {
  name: "obj2",
  bar: obj1.foo,
  obj1: obj1,
};
obj1.foo();//obj1
obj2.obj1.foo();//obj1
obj2.bar();//obj2

规则3:显示绑定

利用函数的call、apply或bind方法,可以将this显式绑定到指定对象上。此时函数中的this将指向该对象:

function foo() {
       console.log(this)
}
var obj = {
   name: "obj"
}
foo.call(obj)
foo()//obj
foo.apply(obj)
foo()//obj
var newfoo = foo.bind(obj)
newfoo()//obj

规则4:new绑定

参考以下代码示例:

function Person(name, age) {
  this.name = name
  this.age = age
  console.log(this)//p
}
var p = new Person("kobe",12);

此处定义了一个构造函数Person,并通过new关键字创建对象。使用new调用构造函数创建对象时,主要经历以下5个步骤:

  • 在内存中创建一个空对象;
  • 将该新对象的[[prototype]]属性指向构造函数的prototype属性;
  • 将构造函数内部的this指向这个新创建的空对象;
  • 开始执行构造函数体内的代码;
  • 若构造函数没有显式返回其他对象,则将该新对象作为返回值返回。

由上述过程可知,在使用new创建对象时,第3步会将构造函数内部的this绑定到新对象上。因此,上述代码中Person函数内打印的this即为通过new关键字创建的对象p。

this绑定的优先级

当多种绑定规则同时存在时,this的指向将依据规则的优先级确定:

  • 默认绑定的优先级最低;
  • 显示绑定优先于隐式绑定。如下列代码所示,打印的this不再是obj,而是String包装对象{'aaa'}:
function foo() {
  console.log(this);//String {'aaa'}
}
var obj = {
  name: "obj",
  foo: foo.bind("aaa"),
};
obj.foo();
  • new绑定优先于隐式绑定。如下列代码所示,打印出的this不是obj,而是新创建的对象f:
var obj = {
  name: "obj",
  foo: function () {
    this.name = "kkk";
    console.log("this:", this);//foo {name: 'kkk'}
  },
};
var f = new obj.foo();
  • new绑定优先于bind绑定(注意:new绑定不能与call、apply同时使用)。如下代码所示,this打印的是obj对象而非String包装对象{'aaa'}:
function foo() {
  console.log(this);
}
var bar = foo.bind("aaa");
var obj = new bar();
//var obj2 = new foo.apply("123");//这样写会报错

除了四个this绑定规则外的特殊情况

1、在显示绑定中,若绑定的值为null或undefined,this将回退到默认绑定,即指向window对象(非严格模式);

function foo() {
  console.log(this)
}
foo.call({})//{}
foo.call(null)//window
foo.call(undefined)//window

2、函数间接引用:在下列代码中,赋值表达式 p.foo = o.foo 的返回值是目标函数的引用,因此实际调用位置是 foo(),而非 o.foo()。所以打印出来的this是window,而不是o或p;

function foo() {
  console.log(this);
}
var o = { foo: foo };
var p = {};
o.foo(); // o
(p.foo = o.foo)(); // window

3、箭头函数:箭头函数自身不绑定this。在调用箭头函数时,其执行上下文中不会生成this记录。若在箭头函数体内使用this,它将在外层作用域中查找this。参考以下代码:

var obj = {
  data: [],
  changeData: function () {
    console.log("普通函数this:", this);
    (() => {
      console.log("箭头函数this:", this);
    })();
    setTimeout(() => {
      this.data = ["1", "2", "3"];
      console.log("this:", this);
    }, 1000);
  },
};
obj.changeData();

打印结果:

this的指向

可以看出,上述打印的this均指向obj。由于箭头函数自身没有this,它向外层作用域查找,找到了changeData函数。此时,由于隐式绑定规则,changeData由obj调用,其this指向obj,因此箭头函数的this也指向obj。

以上就是细说JavaScript中的this指向与绑定规则的详细内容,更多关于JavaScript this的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章