解密 JavaScript 中的 this:作用、行为和陷阱
前言
JavaScript的this关键字是JavaScript中比较重要的概念之一,本文主要讲解this的作用、行为以及使用它会遇到的陷阱。
作用
this主要用于引用对象,可以通过这个关键字访问对象的属性和方法,可以实现动态操作对象,this在不同的上下文中,有不同的行为,接下来我们就讲解一下this的行为。
行为
它在不同上下文中有不同行为,那么我们举一些经典的场景,
普通函数和全局作用域
在普通函数和全局作用域中this的结果为window对象。
function demo(){
console.log(this);
}
console.log(this);
demo()
但严格模式下’use strict’,普通函数this指向为undefined也就是未定义的值。
一层作用域链对象与多层作用域链对象
作用域链是什么?
就是指当前变量或属性所在的作用域层级,作用就是可以防止变量出现内存泄漏情况,且保证变量的隐私性和可访问性,确保在函数嵌套中使用正确的变量。
一层作用域链对象指向该对象本身
let person={
a:'对象属性',
eat:function(){
console.log(this.a)
}
}
person.eat()//对象属性
多层作用链的对象指向的是离的最近的对象。
let person={
a:'对象属性',
eat:function(){
console.log(this.a)
},
b:{
c:'嵌套对象属性',
drink:function(){
console.log(this.c);
}
}
}
person.eat()//对象属性
person.b.drink()//嵌套对象属性
let Per=person.b.drink
Per()//undefined
let PPer=person.b.drink()
PPer()//嵌套对象属性
为什么Per发起调用时,输出的是undefined呢,因为Per被赋值时,并没有调用该drink函数,指把它的属性方法复制进去了,在调用时,默认调用的还是window对象,而window对象中并没有这个name变量所以输出的就是undefined。
但PPer被赋值的就是drink被调用的方法,所以它的this指向的还是离它最近的那个b对象。
注:本质上,在对象中this 指向默认就是创建该方法的对象。
匿名函数
匿名函数是什么?
匿名函数就是没有名称的函数,它可读性较差且调试困难,但它有一定私密性、可以成为回调函数、闭包、私有作用域(立即执行函数表达式(IIFE))等优点。function(),就是匿名函数。它的this指向是比较复杂的,具体分为以下几种情况。
对象中的匿名函数
指向的是对象
let person={
b:function(){
console.log(this);
}
}
person.b()
全局上下文的匿名函数
指向的是window对象
let a=function(){
console.log(this);
}
a()//window
使用call、apply、bind改变匿名函数指向
改变成想要的指向对象。在这里插入代码片
var obj = {
name: 'John'
};
var myFunction = function() {
console.log(this.name);
};
myFunction.call(obj); // 输出:John
myFunction.apply(obj); // 输出:John
var boundFunction = myFunction.bind(obj);
boundFunction(); // 输出:John
call、apply实际是显式改变了prototype原型,相比之下,bind 方法不会立即执行函数,而是返回一个新的函数,该函数具有预先绑定好的执行上下文。这意味着通过 bind 绑定后的函数可以在稍后的时间点调用,其 this 值将始终保持为绑定时的值。
构造函数
指向的是实例化的新对象。
function drink(){
this.orange='dudu'
this.banana='baji'
}
let d=new drink()
console.log(d.orange);//dudu
let e=new drink()
console.log(e.banana);//baji
箭头函数
如果是闭包,上层有非箭头函数,则指向最近的非箭头函数,如果没有,则指向全局对象。
陷阱
在回调函数中,this 的值可能不是我们期望的对象。这是因为回调函数通常在一个不同的上下文中执行,可能会导致 this
指向全局对象或者未定义。为了解决这个问题,可以使用箭头函数或者在调用回调函数之前显式地绑定 this。
使用普通函数作为事件处理程序时,this 的值默认情况下将指向触发事件的元素。但如果使用了箭头函数,则 this
的值将保持为事件绑定时的值,而不会随着事件触发而改变。 在嵌套函数中,this 的值可能会改变。在内部函数中,this
会指向其自己的上下文,而不是外部函数的上下文。要避免这种情况,可以将外部函数的 this 保存到一个变量中,并在内部函数中引用这个变量。