详解JavaScript中的 this 指向

本文深入解析JavaScript中this的绑定机制,包括默认绑定、隐式绑定、显示绑定及new绑定等规则,并探讨箭头函数如何影响this的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

this是在运行时进行绑定的,并不是在在编译时绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用位置。

当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文),而this就是这个记录的一个属性。

this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。

调用位置:

既然this的指向完全取决于函数的调用位置,那么,怎么才能找到函数的调用位置呢?

function a(){

 //a的调用栈为:a
 b();   //b的调用位置
}


function b(){

  //b的调用栈为: a--->b
 c();   //c的调用位置
}


function c(){

  //c的调用栈为: a--->b---->c
 console.log("123");
}
a();   //a的调用位置

你可以把调用栈想象成一个函数调用链,当然你也可以直接用JavaScript调试器查看函数的调用栈。然后找到栈中的第二个元素,这就是真正的调用位置。

this的绑定规则:

上面也已经提到,this是在函数调用时发生的绑定,它指向什么完全取决于函数的调用位置。也就是说,this的绑定规则完全取决于调用位置。

1. 默认绑定

非严格模式下,this 指向 window,  严格模式下 this 指向 undefined。

独立函数调用,就使用的是默认绑定规则。(无法使用其他规则时就会使用默认规则)

 function foo(){
 console.log(this.a);
 }
var a = 2;
foo();     //2

2. 隐式绑定

当函数被调用时,它的前面加上了obj的引用。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。

function foo(){
 console.log(this.a);
}
var obj = {
  a: 2,
  foo: foo
};

obj.foo();   //2

隐式丢失:

 function foo(){
 console.log(this.a);
 }
var obj = {
  a: 2,
  foo: foo
};
var bar = obj.foo;
var a = 3;
bar();   //3

注:虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,此时的bar其实是一个不带任何修饰符的函数调用,因此使用了默认规则。

    function foo(){
  console.log(this.a);
}
function doFoo(fn){

  //fn其实引用的的是foo
 fn(); 
}
var obj = {
  a: 2,
  foo: foo
};
var a = 3;
doFoo( obj.foo );      //3

注:这里需要注意,传参其实就是进行赋值操作。结果是一样的,没有区别。

    function foo(){
 console.log(this.a);
}
var obj = {
  a: 2,
  foo: foo
};
var a = 3;
setTimeout( obj.foo, 100);      // 3 


3. 显示绑定:

    function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
foo.call(obj);   //2

通过foo.call(),我们可以在调用foo时强制把它的this绑定到obj上。

当然,还可以通过appay和bind方法也可以显示的将this绑定到obj上,可以看我后面的文章。

4. new绑定

首先,我先重新定义一下JavaScript中的“构造函数”,在JavaScript中,构造函数只是一些使用new操作符时调用的函数。他们并不会属于某个类,也不会实例化一个类。它们只是被new操作符调用的普通函数而已。

使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

1. 创建(或者说构造)一个全新的对象。

2. 这个新对象会被执行[[Prototype]]连接。

3. 这个新对象会绑定到函数调用的this.

4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

function foo(a){
this.a = a;
}
var bar = new foo(2);
console.log(bar.a);   //2

四种绑定规则的优先级:

new绑定 > 显示绑定 > 隐式绑定 > 默认绑定


判断this:

1.函数是否在new中调用(new绑定),如果是的话this绑定的是新创建的对象。

2. 函数是否通过call,apply(显示绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对 象。

3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。

4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象


当然,凡事都有例外,上面所说的适用于绝大多数情况,但也有一些例外:

如果你把null或者undefined作为this的绑定对象传入call,apply,bind,这些值在调用时会被忽略,实际应用的是默认的绑定规则。

function foo(){
console.log(this.a);
}
var a = 2;
foo.call(null);   //2


箭头函数:

箭头函数并不是使用function关键字定义的,而是使用被称为“胖箭头”的操作符=>定义的,箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。也就是说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。

function foo(){
return (a) => {
console.log(this.a);
};
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
var bar = foo.call(obj1);
bar.call(obj2);    //2 , 不是3!!!


注:还有一点需要注意,箭头函数的绑定无法被修改。(new也不行)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值