js中的this问题总结

关于this的指向问题算的上是js中的一个十分重要的问题了。今天把这个问题总结下,加深下自己对this的理解。首先,this的指向问题可以用一句话总结就是:this总是指向调用的对象,也就是说this指向谁与函数声明的位置没有关系,只与调用的位置有关。这是判断this的一个大体原则,而具体的小原则按照优先级的不同大致可以分为以下几点:

一.优先级:new绑定>显式绑定>隐式绑定>默认绑定

1.new绑定
new方式是优先级最高的一种调用方式,也就是说只要是出现new方式来调用一个函数,this肯定会指向new调用函数新创建的对象。

function thisTo(a){
 this.a=a;
}
var data=new thisTo(2); //在这里进行了new绑定
console.log(data.a);  //2

2.显式绑定
显示绑定指的是通过call()和apply()方法对函数进行的调用,对this影响的优先级仅次于new绑定。

function thisTo(){
   console.log(this.a);
}
var data={
    a:2
}; 
thisTo.call(data));  //2

3.隐式绑定
隐式绑定是指通过对象的属性进行添加,从而调用this所在函数,该方式的优先级在显示绑定之后。

function thisTo(){
   console.log(this.a);
}
var data={
    a:2,
    foo:thisTo //通过属性引用this所在函数 
};
data.foo(); //2

4.默认绑定
默认绑定是指当上面这三条绑定规则都不符合时采用的绑定规则,默认绑定会把this默认绑定到全局对象中,是优先级最低的绑定规则。

function thisTo(){
   console.log(this.a);
}
var a=2; //a是全局对象的一个同名属性
thisTo(); //2

二.this绑定的特殊情况

1.隐式丢失
当进行隐式绑定时,如果进行一次引用赋值或者传参操作,会造成this的丢失,从而最后将this绑定到全局对象中去。

1.1 引用赋值丢失

function thisTo(){
   console.log(this.a);
}
var data={
    a:2,
    foo:thisTo //通过属性引用this所在函数 
};
var a=3;//全局属性

var newData=data.foo; //这里进行了一次引用赋值 
newData(); // 3

原理:因为newData实际上引用的是foo函数本身,跟data对象没有任何关系,data对象只是一个中间桥梁。而newData就是一个本身不带a属性的对象,自然最后只能把a绑定到全局对象上了。

1.2传参丢失

function thisTo(){
   console.log(this.a);
}
var data={
    a:2,
    foo:thisTo //通过属性引用this所在函数 
};
var a=3;//全局属性

setTimeout(data.foo,100);// 3

原理:setTimeout(fn,delay) { fn(); } 实际上fn是一个参数传递的引用(fn=data.foo),与引用丢失的原理一样

1.3 Function.prototype.bind()
为了解决隐式丢失的问题,ES5提供了bind方法,bind()会返回一个硬编码的新函数,它会把参数设置为this的上下文并调用原始函数。

function thisTo(){
   console.log(this.a);
}
var data={
    a:2
}; 
var a=3;
var bar=thisTo.bind(data);
console.log(bar()); //2

2.间接引用
间接引用是指一个定义对象的方法引用另一个对象存在的方法,这种情况下会使得this进行默认绑定。

function thisTo(){
   console.log(this.a);
}
var data={
  a:2,
  foo:thisTo
};
var newData={
  a:3
}
var a=4;
data.foo(); //2
(newData.foo=data.foo)() //4

原理:newData.foo=data.foo的返回值是目标函数的引用,因此调用的位置实际上是foo(),根据之前的隐式丢失里面说的原则,这里会应用默认绑定。

3.ES6箭头函数
ES6的箭头函数在this这块是一个特殊的改进,箭头函数使用了词法作用域取代了传统的this机制,所以箭头函数无法使用上面所说的这些this优先级的原则,注意的是在箭头函数中,是根据外层父亲作用域来决定this的指向问题。

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

不用箭头函数,发生隐式丢失,最后的this默认绑定到全局作用域,输出3。

function thisTo(){
   setTimeout(()=>{
    console.log(this.a);
},100);
}
var obj={
 a:2
}
var a=3;加粗文字
thisTo.call(obj); //2

用了箭头函数,不会发生隐式丢失,this绑定到外层父作用域thisTO(),thisTo的被调用者是obj对象,所以最后的this到obj对象中,输出2。

如果不用箭头函数实现相同的输出,可以采用下面这种方式:

function thisTo(){
   var self=this; //在当前作用域中捕获this 
   setTimeout(function(){
    console.log(self.a); //传入self代替之前的this
},100);
}
var obj={
 a:2
}
var a=3;
thisTo.call(obj); //2

三.总结:
this的绑定机制,就是要找到这个函数的直接调用位置,然后应用绑定的四条规则,当出现满足多个规则时,按照优先级的高低决定最终的绑定规则。此外注意几种特殊情况,特别是ES6中的箭头函数。

<think>好的,我现在需要帮助用户理解JavaScript中的`this`问题。用户之前询问过`call()`方法,现在可能对`this`的绑定机制有更深入的兴趣。首先,我要确保覆盖`this`的不同使用场景,因为`this`的指向容易让初学者困惑。 首先,我应该回顾用户之前的对话,看看他们是否已经了解`call()`,因为`call()`和`apply()`、`bind()`都是显式绑定`this`的方法。用户可能已经知道如何通过`call()`改变`this`,现在想全面了解`this`的各种情况。 接下来,我需要列举`this`的四种绑定规则:默认绑定、隐式绑定、显式绑定和new绑定。用户可能遇到的情况包括函数调用、对象方法、构造函数以及箭头函数。特别是箭头函数的`this`行为与传统函数不同,需要特别说明。 然后,我要考虑用户可能的疑问点。例如,事件处理函数中的`this`指向,或者回调函数中`this`丢失的问题。这时候可能需要提到`bind()`或者箭头函数如何解决这类问题。 还要注意严格模式下的差异,比如默认绑定中`this`会是undefined,而普通模式下是全局对象。这点容易出错,需要强调。 另外,用户可能在实际项目中遇到`this`指向不符合预期的情况,比如在嵌套函数或定时器中。这时候需要给出实际的例子,说明如何正确绑定`this`。 最后,应该总结常见问题和解决方案,帮助用户快速查阅。比如使用`self = this`、箭头函数或显式绑定方法。同时,提醒用户注意使用严格模式的影响,以及箭头函数不能作为构造函数的特点。 需要确保语言简洁明了,结构清晰,分点说明,并辅以代码示例。避免使用过于专业的术语,让不同层次的用户都能理解。可能还需要对比不同绑定方式之间的区别,帮助用户加深记忆。 检查是否有遗漏的重要知识点,比如构造函数中的`this`指向实例,或者回调函数中的`this`问题。确保覆盖所有常见场景,并提供足够的示例代码,帮助用户通过实践理解理论。 最后,组织内容结构,先讲基本概念,再分点详细说明每种绑定规则,接着讨论特殊情况,最后总结常见问题和解决方案。这样用户可以从基础到进阶逐步理解,同时方便他们遇到问题时快速查找解决方法。</think>以下是JavaScript中`this`关键字的详细解析,包含核心规则和常见问题: --- ### 一、`this`的绑定规则 | 绑定类型 | 触发条件 | `this`指向 | 示例代码片段 | |---------------|-------------------------|---------------------|---------------------------------------| | **默认绑定** | 独立函数调用 | 全局对象(非严格模式)<br>`undefined`(严格模式) | `function foo(){ console.log(this) }`<br>`foo()` | | **隐式绑定** | 通过对象调用方法 | 调用方法的对象 | `obj.fn()` → `this`指向`obj` | | **显式绑定** | 使用`call/apply/bind` | 指定的第一个参数 | `fn.call(targetObj)` → `this`指向`targetObj` | | **new绑定** | 使用`new`构造函数 | 新创建的实例对象 | `new Person()` → `this`指向实例 | --- ### 二、特殊场景分析 #### 1. 嵌套函数中的`this` ```javascript const obj = { name: "obj", outer() { function inner() { console.log(this.name); // 输出undefined(默认绑定到全局) } inner(); } }; obj.outer(); ``` **解决方法**:使用箭头函数或闭包保存`this` ```javascript outer() { const self = this; // 保存外层this function inner() { console.log(self.name); // 正确输出"obj" } inner(); } ``` #### 2. 回调函数中的`this` ```javascript const btn = document.querySelector("button"); btn.addEventListener("click", function() { console.log(this); // 指向触发事件的DOM元素(隐式绑定) }); // 定时器回调 setTimeout(function() { console.log(this); // 默认绑定到全局对象(浏览器中是window) }, 100); ``` #### 3. 箭头函数的`this` ```javascript const obj = { value: 42, getValue: () => { console.log(this.value); // 输出undefined(继承外层this) }, getValueNormal() { const arrowFn = () => { console.log(this.value); // 正确输出42(继承getValueNormal的this) }; arrowFn(); } }; ``` --- ### 三、优先级排序 $$显式绑定 > new绑定 > 隐式绑定 > 默认绑定$$ --- ### 四、常见问题解答 #### Q1:为什么事件处理函数中的`this`指向DOM元素? - **答**:浏览器在调用事件处理函数时,会通过隐式绑定将`this`设置为触发事件的元素 #### Q2:如何强制固定`this`指向? - **方案**: 1. `bind()`方法创建绑定函数 ```javascript const boundFn = originalFn.bind(targetThis); ``` 2. 箭头函数自动继承外层`this` ```javascript const obj = { data: "test", handler: () => { /* 自动绑定定义时的this */ } }; ``` #### Q3:严格模式对`this`的影响? - **关键变化**: - 默认绑定的`this`变为`undefined` - 禁止使用`call()`/`apply()`将`this`指向原始值(数字/字符串等) --- ### 五、实践建议 1. 使用`console.log(this)`实时验证指向 2. 优先使用箭头函数处理需要固定上下文的场景 3. 在构造函数中必须使用`new`调用,避免`this`泄漏到全局 4. 对回调函数建议显式绑定`this`(如`arr.map(function(){}.bind(this))`) 通过理解这些规则,可以更精准地控制`this`的指向,避免常见错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值