this关键字
大约 6 分钟
this关键字
什么是this关键字?
在编程中,this是一个特殊的关键字,它指向当前执行上下文的对象。this的具体含义和行为会根据使用场景而变化。在非严格模式下,this总是指向一个对象,而在严格模式下可以是任何值。
this在不同情况下的指向:
- **全局上下文:**在全局执行上下文中(任何函数外部),this指向全局对象。在浏览器中,它通常指向window对象。
- **函数上下文:**在函数内部,this的值取决于函数的调用方式。
- **对象方法:**当函数作为对象的方法被调用时,this通常指向该对象。
- **构造函数:**使用new关键字调用函数时,this指向新创建的对象实例。
- **事件处理程序:**在DOM事件处理程序中,this通常指向触发事件的元素。
this的常见用途:
- 在对象方法中访问对象的其他属性或方法。
- 在构造函数中初始化新创建的对象实例。
- 在事件处理程序中引用触发事件的元素。
- 实现对象的继承和多态性。
注意事项:
this的行为可能会因为箭头函数和严格模式等因素而发生变化。理解和正确使用this是掌握JavaScript等面向对象编程语言的关键。
全局环境下的this
// 以普通函数的形式调用
function fn1() {
console.log(this);
}
fn1(); // this 指向全局对象 window/global
-----------------------------------------------------------------------------------
// 严格模式下
function fn2() {
"use strict";
console.log(this);
}
fn2(); // this 指向 undefined
-----------------------------------------------------------------------------------
// 函数作为对象的方法调用
var foo = {
bar: 10,
func() {
console.log(this);
console.log(this.bar);
},
};
var fn2 = foo.func;
fn2(); // this 指向全局对象 window/global
foo.func(); // this 指向 foo上下文对象调用中的this
// 函数作为对象方法被调用时,this 指向该对象
var stu = {
name: "张三",
fn() {
return this;
},
};
console.log(stu.fn() === stu); // true
----------------------------------------------------------------------------------
var stu = {
name: "张三",
son: {
name: "李四",
fn() {
return this.name;
},
},
};
console.log(stu.son.fn()); // 李四
-----------------------------------------------------------------------------------
var o1 = {
text: "01",
fn() {
return this.text;
},
};
var o2 = {
text: "02",
fn() {
return o1.fn();
},
};
var o3 = {
text: "03",
fn() {
var fn2 = o1.fn;
return fn2(); // 这里相当于普通函数的形式被调用
},
};
console.log(o1.fn()); // 01
console.log(o2.fn()); // 01
console.log(o3.fn()); // undefinedthis指向绑定事件的元素
例1:
<ul id="list">
<li>Lorem, ipsum.</li>
<li>Voluptas, facere.</li>
<li>Veniam, pariatur.</li>
<li>Provident, mollitia!</li>
<li>Explicabo, excepturi!</li>
<li>Iusto, sapiente.</li>
</ul> // this 是绑定事件的元素
// target 是事件触发的元素,与 srcElement 一样
let list = document.getElementById("list");
list.addEventListener("click", function (e) {
console.log('this', this); // ul
console.log('target', e.target); // 当前所点击的 li
console.log('srcElement', e.srcElement); // 当前所点击的 li
});例2:
<div id="div1">我是一个 div</div> window.id = "window";
document.getElementById("div1").onclick = function () {
console.log(this.id); // div1
const that = this; // this
const callback = function () {
console.log(this.id); // window
console.log(that.id); // div1
};
callback();
};改变 this 指向
call
Function实例的**call()**方法会给出确定的this值并逐个提供参数来调用该函数。
/**
* call
* Function 实例的 call() 方法会以给定的 this 值和逐个提供的参数调用该函数。
*/
var obj = { value: 1 };
function bar() {
return this;
}
console.log(bar() === global); // true;
console.log(bar.call(obj) === obj); // true
console.log(bar.call()); // global
console.log(bar.call(null) === global); // true
console.log(bar.call(undefined) === global); // true
// 总之,call() 方法改变 this 的指向就是你传入的对象。如果call传入的参数不是以上类型,则转换为对应的包装对象,然后传入方法
var f = function(){
return this;
}
f.call(5) // [Number: 5]call可以接受多个参数,这些参数会传递给前面的方法
function add(a, b) {
return a + b;
}
console.log(add.call(null, 1, 2)); // 3
------------------------------------------------------------------------------------
var obj = {};
// hasOwnProperty() 方法返回一个布尔值,表示对象自有属性(而不是继承来的属性)中是否具有指定的属性。
console.log(obj.hasOwnProperty("toString")); // false
console.log(obj.toString()); // [object Object]
console.log(
// Object.prototype.hasOwnProperty 方法来检查 obj 是否有 "toString" 属性。
// 通过 call 方法,我们将 obj 作为上下文传递给 hasOwnProperty。
// 结果仍然是 false,因为 toString 是从原型链继承来的,而不是 obj 的自有属性。
Object.prototype.hasOwnProperty.call(obj, "toString") // false
);apply
Function 实例的 apply() 方法会以给定的 this 值和作为数组(或类数组对象)提供的 arguments 调用该函数。
var arr = [1, 2, 3];
console.log(Math.max.apply(null, arr));
// slice() 方法会读取 this 对象的 length 属性,然后从 start 到 end 读取整数键属性,并将它们定义在一个新创建的数组中。
console.log(Array.prototype.slice.apply({ 0: 1, 1: 2, 2: 3 })); // []
console.log(Array.prototype.slice.apply({ 0: 1, 1: 2, 2: 3, length: 3 })); // [ 1, 2, 3 ]bind
Function 实例的 bind() 方法创建一个新函数。当调用该新函数时,它会调用原始函数并将其 this 关键字设置为给定的值。同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数之前。
var d = new Date();
var t = d.getTime;
t(); // this is not a Date object.
var fn = d.getTime.bind(d);
console.log(fn());
------------------------------------------------------------------------------------
var obj = {
name: "John",
arr: [1, 2, 3],
// print() {
// this.arr.forEach(function (item) { // 在这里,我们使用了一个普通的函数表达式(function (item) { ... })作为回调。
// console.log(this.name); // 这里的 this 指向全局对象,而不是 obj 对象。
// console.log(this === globalThis); // true
// });
// },
print() {
this.arr.forEach(
function (item) {
console.log(this.name); // 这里的 this 指向 obj
console.log(this === globalThis); // false
}.bind(this)
); // 通过在回调函数后面调用 .bind(this),我们将 this 的上下文显式地绑定到 print 方法的上下文(即 obj 对象)。
},
};
obj.print();
// this 被绑定为 Array.prototype。
var slice = Function.prototype.call.bind(Array.prototype.slice);
// 调用 slice 函数时,它实际上是在调用 Array.prototype.slice,并且 this 将指向我们传入的数组。
console.log(slice([1,2,3], 0, 2));箭头函数的this指向
- 箭头函数没有独立的
this、arguments和super绑定,并且不可被用作方法。 - 箭头函数不能用作构造函数。使用
new调用它们会引发TypeError。它们也无法访问new.target关键字。 - 箭头函数不能在其主体中使用
yield,也不能作为生成器函数创建。
const obj = {
name: "Alice",
greet: function() {
console.log("Inside greet:", this.name); // Alice
const innerFunction = () => {
console.log("Inside innerFunction:", this.name); // Alice
};
innerFunction();
}
};
obj.greet();总结
- 在函数体中,进行非显式或隐式的简单函数调用时,严格模式下的
this绑定到undefined。而在非严格模式下,this则会绑定到全局对象(在浏览器中为window,在 Node.js 中为global)。 - 当使用
new关键字调用构造函数时,构造函数内的this会被绑定到新创建的对象上。这样,新对象可以继承构造函数中定义的属性和方法。 - 通过
call、apply或bind方法显式调用函数时,函数体内的this会被绑定到传入的参数对象上。这种方式允许你控制函数执行时的上下文。 - 当通过上下文对象调用函数时,函数体内的
this会被绑定到该对象。这种调用方式使得函数能够访问和操作调用它的对象的属性和方法。 - 箭头函数的
this绑定与常规函数不同。箭头函数的this指向由其外层作用域决定,而不是由调用方式决定。这意味着箭头函数不会创建自己的this,而是从外层函数或全局上下文中继承。
