一、js 中 this 是什么
this 是函数执行时所在的上下文环境
二、this 的指向
js 全局对象:在 html 页面中引入的 js 文件 全局对象 是 window 对象,使用 node 命令执行 js 文件 全局对象 是 global 对象
1. 在 js 文件外层 this 指向 全局对象
console.log(this); // 全局对象
2. 在函数中 this 指向
- 在严格模式下,this 指向的是 undefined
"use strict";
function a() {
console.log(this); // undefined
}
a();
- 在非严格模式下,如果把函数当作构造函数使用:this 指向这个构造函数创建的实例对象
// 构造函数
function A() {
this.name = "alias";
this.age = 20;
this.show = ()=>{
console.log(this);
}
}
console.log(new A()); // {name: 'alias', age: 20}
new A().show() // {name: 'alias', age: 20}
console.log(window.age); // undefined , 说明构造函数中的this不指向全局对象
- 在非严格模式下,如果把函数当作普通函数调用:this 指向函数运行时所在的上下文环境
即:在 script 标签外层的调用函数:this 指向全局对象,以对象的方法的方式调用函数:this 指向方法所在的对象
// 外层直接调用:this 是全局对象
function a() {
this.username = "alias";
this.password = 123456;
}
a();
console.log(window.username); // alias
console.log(this.username); // alias
// 对象方法:this 的指向取决于调用对象方法的方式
const objB = {
xcxv: "xcxv",
getXcxv() {
console.log(this.xcxv);
},
};
objB.getXcxv(); // alias , 以对象的方法的方式调用:this 指向对象方法所在的对象
const bbb = objB.getXcxv;
bbb(); // undefined, 将对象的方法取出并在 script 标签外层调用:this 指向全局对象
- 在事件中 this 指向当前事件所在的 dom 元素
<div onclick="show(this)">hello world</div>
<script>
function show(params) {
console.log(params); // 当前dom元素 <div onclick="show(this)">hello world</div>
}
</script>
三、临时改变 this 指向的三个方法 call、apply、bind
- call、apply、bind 三者都可改变 this 的指向,且都只是临时的改变 this 的指向
- call 和 bind 方法传参方式一样,第一个参数是 this 指向的实例对象,其他是方法参数,以逗号隔开,区别是 bind 方法不立即执行,需要以方法的方式调用
- apply 方法,第一个参数是 this 指向的实例对象,其他是方法参数,放在数组中以逗号隔开
- call、apply、bind 方法使用示例
// 让 A 的 this 指向 B,并调用 A 函数,此时 A 和 B 的实例属性会合并
function A(p1, p2) {
this.a = 'AAAAA'
this.p1 = p1
this.p2 = p2
console.log(this);
}
var B = { b: "BBBBB" };
A.call(B, "x", "xx"); // 结果: { name: 'B' } x xx
A.apply(B, ["x", "xx"]); // 结果: { name: 'B' } x xx
A.bind(B, "x", "xx")(); // 结果: { name: 'B' } x xx
new A() //结果: {a: 'AAAAA', p1: undefined, p2: undefined},说明改变 this 指向只是临时的
- 在借用构造函数继承中,使用 call、apply,让子类继承父类的实例属性
// 父类
function A() {
this.name = "AAAAAAA";
this.age = 18;
}
// 子类
function B() {
this.BBBBB = "BBBBB"; // 与父类不同名的属性可以写在 A.call(this) 上面
A.call(this) // 将父类 A 的 this 指向子类 B 实例对象,并执行 A,此时 A 和 B 的实例属性会合并,也就是B继承了A实例属性(函数中this总是指向实例对象)
this.name = "B"; // 与父类同名的属性要写在 A.call(this) 下面,否则会在 A.call(this) 时被父类属性覆盖掉
}
console.log(new (A)); // {name: 'AAAAAAA', age: 18}
console.log(new (B)); // {BBBBB: 'BBBBB', name: 'B', age: 18}