this
JavaScript中的this的值取决于函数调用的上下文。
全局上下文
在全局执行上下文中(在任何函数之外),this无论是严格模式还是非严格模式下,都引用全局对象。 在web浏览器中,this引用的是window对象,可以在浏览器中打印console.log(this);而在Node.js中,引用的是global。
函数上下文
在普通函数内部,this 的值取决于函数的调用方式。如果函数在全局上下文中调用,this 在严格模式下将为 undefined,在非严格模式下将引用全局对象。
function func() {
console.log(this);
}
func(); // 在非严格模式的浏览器上下文中记录 "[object Window]",在严格模式下会记录 "undefined"当函数充当对象的方法时,this将引用调用该方法的对象。这展示了this的值不绑定于函数本身,而是由函数被调用的方式和位置决定,这个概念称为执行上下文:
let obj = {
prop: "Hello World!",
func: function() {
console.log(this.prop);
}
}
obj.func(); // "Hello World!"要注意的是,箭头函数没有自己的this,箭头函数内部的this不由它的调用方式决定,而是由定义时的外部词法上下文决定。
let obj = {
prop: "Hello World!",
func: ()=> {
console.log(this.prop);
}
}
obj.func(); // "undefined",this不指向到obj,而是其外部词法上下文事件处理程序
在事件处理程序的上下文中,this引用附加了事件监听器的元素,与event.currentTarget相同。
在此之前,先要了解event.target与event.currentTarget的区别:
event.target:该属性引用引发事件的实际DOM元素。对于会冒泡的事件特别重要。如果你点击内部元素,事件将冒泡到外部元素,触发它们的事件监听器。event.currentTarget:该属性引用附加了事件处理程序(如:addEventListener)的元素。这是在事件处理程序函数的上下文中this引用的内容。
例如:
<div id="outer">外部元素
<div id="inner">内部元素</div>
</div>
<script>
document.getElementById('outer').addEventListener('click', function(event) {
console.log("currentTarget: ", event.currentTarget.id);
console.log("this: ", event.currentTarget.id);
console.log("target: ", event.target.id);
});
</script>当点击外部元素时,三个都打印为outer。
当点击内部元素时,event.target.id将打印为inner,这是当前点击的元素;而event.currentTarget.id和event.currentTarget.id将仍然打印为outer,因为这是事件处理程序附加的元素。
构造函数上下文和类上下文
在这两种上下文中,跟其他的面向对象语言相似,构造函数上下文中会根据new关键字来变更this指向为新对象;类上下文中也同样会引用类的实例。
显示/隐式绑定
可以使用函数上的 .call()、.apply() 或 .bind() 方法来明确设置 this 的上下文:
function logThis(age, name) {
console.log(this, age, name);
}
const people = { number: 1 };
logThis.call(people, "18", "小红"); // {number: 1} '18' '小红'
logThis.apply(people, ["25", "小华"]); // {number: 1} '25' '小华',apply 与 call 的区别在于参数的传递方式
const boundLogThis = logThis.bind(people, "55", "老徐");
boundLogThis(); // {number: 1} '55' '老徐',返回新函数,非立即执行
boundLogThis.call(people, "18", "小徐"); // {number: 1} '55' '老徐',bind 之后无法再改变 this 的指向.call()、.apply() 和 .bind() 的区别在于:
.call()和.apply()立即调用函数,.call()接受参数列表,.apply()接受参数数组。.call()比.apply()的性能要好,尤其是传入参数超过三个以上的时候。.bind()不会立即执行,返回一个新函数,它的this值永久绑定到指定的对象。
使用场景
场景1: apply
let arr = [1, 2, 3, 4, 5];
console.log(Math.max.apply(null, arr)); // 5场景2: bind
<!DOCTYPE html>
<html>
<body>
<button id="btn">点击</button>
<button id="chuo">戳一戳</button>
<script>
var btn = document.getElementById('btn');
var chuo = document.getElementById('chuo');
// onclick需要一个函数,而不是一个对象,所以使用bind
btn.onclick = function() {
console.log(this); // <button id="chuo">戳一戳</button>
}.bind(chuo);
</script>
</body>
</html>绑定方法和永久this上下文
bind 方法创建一个新函数,当调用时,将其 this 关键字设置为提供的值,以及在调用新函数时提供的一系列参数。
bind 方法的独特之处在于它创建了一个永久绑定的 this 值,无论后来如何调用该函数,都不会更改 this 的值。例如:
function greet() {
return `你好,我是 ${this.name}`;
}
let person1 = { name: 'Rarrot' };
let person2 = { name: '666' };
// 创建一个与 `person1` 绑定的函数
let greetPerson1 = greet.bind(person1);
console.log(greetPerson1()); // 你好,我是 Rarrot
// 尝试使用 `call` 方法更改上下文;但是,它仍然使用 `person1` 作为 `this` 上下文
console.log(greetPerson1.call(person2)); // 你好,我是 Rarrot
// 相比之下,正常函数调用允许使用 `call` 方法设置 `this` 上下文
console.log(greet.call(person2)); // 你好,我是 666以下为什么在浏览器中输出为underfined和6?
// 'use strict',在严格模式下,x为underfined,不能进行设置值
function a(xx) {
this.x = xx;//this指向全局对象,而不是函数内部的作用域。
return this
};
//a(5)表示对this指向的全局对象的属性x赋值,x赋值为5,
//所以由打印此全局对象的x属性为5。
var x = a(5);
//相当于a(5).x
console.log(x.x)
var y = a(6);
//返回的x为全局对象,前面由于调用了a(6),所以此时this指向的全局对象的属性x值为6
console.log(x.x)
//相当于a(6).x,可得出a(6)返回的对象的属性x=6。
console.log(y.x)总结
全局对象中的
this指向指向的是
window全局作用域或者普通函数中的
this指向全局
windowthis永远指向最后调用它的那个对象在不是箭头函数的情况下
new操作符改变了
this的指向apply,call,bind改变
this指向在不是箭头函数的情况下
箭头函数的
this它的指向在定义的时候已经确定了 箭头函数它没有
this,看外层是否有函数,有就是外层函数的this,没有就是window匿名函数中的
this永远指向了
window,匿名函数的执行环境具有全局性,因此this指向window
