JavaScript this的指向和改变this指向的方法
2024-04-10 06:40:23  阅读数 489

一、js 中 this 是什么

this 是函数执行时所在的上下文环境

二、this 的指向

js 全局对象:在 html 页面中引入的 js 文件 全局对象 是 window 对象,使用 node 命令执行 js 文件 全局对象 是 global 对象

1. 在 js 文件外层 this 指向 全局对象

console.log(this); // 全局对象

2. 在函数中 this 指向

  1. 在严格模式下,this 指向的是 undefined
"use strict";
function a() {
  console.log(this); // undefined
}
a();
  1. 在非严格模式下,如果把函数当作构造函数使用: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不指向全局对象
  1. 在非严格模式下,如果把函数当作普通函数调用: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 指向全局对象
  1. 在事件中 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

  1. call、apply、bind 三者都可改变 this 的指向,且都只是临时的改变 this 的指向
  2. call 和 bind 方法传参方式一样,第一个参数是 this 指向的实例对象,其他是方法参数,以逗号隔开,区别是 bind 方法不立即执行,需要以方法的方式调用
  3. apply 方法,第一个参数是 this 指向的实例对象,其他是方法参数,放在数组中以逗号隔开
  1. 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 指向只是临时的
  1. 在借用构造函数继承中,使用 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}