this对象的定义
- this 是指函数被调用时的
上下文
- this对象 代表了
当前执行上下文
的主体对象
- this指向最后一次调用这个方法的对象
- this的值 并不是在函数定义时确定的,而是在
函数被调用时确定的
this的指向
在实际开发中,this 的指向一般可以通过四种调用模式来判断:
1. 函数调用(默认绑定)
当一个函数不是一个对象的属性时,直接作为函数来调用时,this的值在非严格模式下为全局对象
(在浏览器环境中为window
),在严格模式下为undefined
kotlin
function fun() {
console.log(this);
}
fun(); // 非严格模式下输出window,严格模式下输出undefined
var name = 'Jenny';
function person() {
return this.name;
}
console.log(person()); // Jenny
2. 方法调用(隐式绑定)
-
如果一个函数作为一个
对象的方法
来调用时,this 指向这个对象
(实例一) -
若函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this 指向的也只是它
上一级
的对象(实例二) -
函数this 永远指向的是
最后
调用它的对象(实例三)
javascript
// 实例一
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m(); // 1
var obj = {
a:10,
b:{
fn:function(){
console.log(this.a); // undefined
}
}
}
obj.b.fn();
var obj = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); // undefined
console.log(this); // window
}
}
}
var j = obj.b.fn;
j();
/*
此时 this 指向的是 window,这里的大家需要记住,this 永远指向的是最后调用它的对象,虽
然fn 是对象b 的方法,但是 fn 赋值给 j时候并没有执行,所以最终指向 window */
3. 构造函数调用(new 绑定)
- 如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个
新创建的对象
(实例一) - new过程中遇到
return一个对象
时,此时this指向为return的对象
(实例二) - new过程中遇到
return一个简单类型
或者null
时,此时this仍然指向实例对象
(实例三)
javascript
// 实例一
function Test(value) {
this.value = value;
}
var obj = new Test(8);
console.log(obj.value); // 输出8
// 实例二
function fn(){
this.user = 'xxx';
return {};
}
var a = new fn();
console.log(a.user); // undefined
// 实例三
function fn(){
this.user = 'xxx';
return 1; // 或者 return null
}
var a = new fn;
console.log(a.user); //xxx
4. apply 、 call 和 bind 调用模式(显示绑定)
call、apply、bind的共同点:
- 这三个方法都可以显示的指定调用函数的 this 指向
- 它们的第一个参数就表示改变后调用这个函数的对象即
this指向的就是第一个参数
。 - 第一个参数是
null
或者undefined
时,默认指向window
(浏览器)
call、apply、bind的区别:
-
call方法接收两个参数,第一个参数是this的值,第二个参数是传递给函数的参数,以
逗号分隔
,参数一次性传入。改变this指向后原函数会立即执行
,此方法只临时改变
this指向一次
。 -
apply方法也接收两个参数,第一个参数是this的值(为
null
或者undefined
时,默认指向window
(浏览器)),第二个参数一个数组或类数组对象
,改变this指向后原函数会立即执行
,此方法只临时改变
this指向一次
。 -
bind方法创建一个新的函数,当这个新函数被调用时,bind的第一个参数将作为它运行时的this,参数可分
多次传入
。改变this指向不会立即执行
,而是返回一个永久改变this指向的函数
。
scss
function fn(...args){
console.log(this,args);
}
let obj = {
myname:"xxx"
}
// apply
fn.apply(obj,[1,2]);
// call
fn.call(obj,1,2);
const bindFn = fn.bind(obj); // this指向obj
// bind不会理解执行需要执行一次
bindFn(1,2) // this指向obj
fn() // this指向window
小结
- 在全局的环境下this是指向window
- 普通函数调用直接调用中的this 会指向 window
- 严格模式下this会指向 undefined
- 自执行函数 this 指向 window
- 定时器中的 this 指向 window
- 在对象里调用的this,指向调用函数的那个对象
- 在构造函数以及类中的this,构造函数配合 new 使用, 而 new 关键字会将构造函数中的 this 指向实例化对象,所以构造函数中的 this 指向 当前实例化的对象
- 方法中的this谁调用就指向谁。
- 箭头函数没有自己的 this,箭头函数的this在定义的时候,会继承自外层第一个普通函数的this
箭头函数
- 在ES6中的箭头函数语法,让我们在
书写
时就能确定this的指向
(编译时绑定
)(实例一)
箭头函数的坑:
- 绑定监听事件(实例二)
- 原型上添加方法(实例三)
- 箭头函数不能作为构建函数
javascript
// 实例一
const obj = {
sayThis: () => {
console.log(this);
}
};
obj.sayThis(); // window
// 因为JavaScript没有块作用域,所以在定义sayThis时,里面的this就绑定到window了
const globalSay = obj.sayThis;
globalSay(); // window
// 实例二
const button = document.getElementById('mngb');
button.addEventListener('click', ()=> {
console.log(this === window) // true
this.innerHTML = 'clicked button'
})
// 实例三
Cat.prototype.sayName = () => {
console.log(this === window) //true
return this.name
}
const cat = new Cat('mm');
cat.sayName()
this的绑定规则
根据不同的使用场合,this 有不同的值,主要分为下面几种情况:
- 默认绑定
- 隐式绑定
- new绑定
- 显示绑定
优先级
new绑定优先级>显示绑定优先级>隐式绑定优先级>默认绑定优先级>
使用this 时常见的问题以及解决方案
- 常见问题 :在回调函数、定时器或事件处理程序中,由于
this
的绑定规则,可能会导致this
指向不正确。 - 解决方案:
- 使用箭头函数来避免
this
绑定问题。 - 使用
.bind(this)
显式绑定this
。 - 在函数外部保存
this
的引用,如const self = this;
。
通过理解和掌握this
在不同上下文中的行为,以及call
、apply
和bind
方法的使用,你可以更有效地控制JavaScript中的this
指向,从而编写出更加健壮和可维护的代码。