hzzzzzzzq / Blog

这是我记录博客的地方,希望能多写一些技术博客,JS、ES、React、Vue等
14 stars 0 forks source link

深入理解JavaScript系列(5):this #46

Open hzzzzzzzq opened 2 years ago

hzzzzzzzq commented 2 years ago

JavaScript 深入之 this

在[《JavaScript 深入之执行上下文栈》]()中提到,当 JavaScript 代码执行代码时,就会创建一个执行上下文。

对于执行上下文,都有三个重要属性:

我们来介绍一下 this。

this

什么是 this 呢?我们可以把 this 的指向当作执行时所指向的执行上下文。在不同的上下文中,this 的确定经常会发生问题。

this 是执行上下文中的一个属性。

globalContext = {
  VO: {...},
  this: globalContext.VO,
}

VO 就是上一节讲到的变量对象了。

this 与上下文中可执行代码的类型有直接关系,this 值在进入上下文时确定,并且在上下文运行期间永久不变

全局代码中的 this

全局代码中的 this 始终是全局对象本身。

this.a = 1;
console.log(a); // 1

b = 2;
console.log(this.b); // 2

var c = 3;
console.log(this.c); // 3

那么全局对象本身是什么呢?在浏览器中就是我们经常使用的 window

console.log(this); // window 对象
console.log(window); // window 对象
console.log(this === window); // true

函数中的 this

函数中的 this 是很奇特的,也是很有趣的。它的指向并不是固定的,而且可以通过手动进行修改。

我们在上面介绍到,this 是进入上下文时确定,所以在一个函数代码中,这个值在每一次完全不同。

注意:任何时候不能改变 this 的值。

let objBind = { value: 2 };
let obj = {
  value: 1,
  test: function () {
    console.log(this === obj);
    console.log(this.value);
    // this = objBind; // 报错,任何时候不能改变 this 的值
    // console.log(this.value);
  },
};

// 我们来执行一下
obj.test(); // true, 1

objBind.test = obj.test;

objBind.test(); // false, 2

我们看到结果的结果是不同的。 发现,指向的结果是不是跟调用它的对象有关呢?事实就是这样,谁调用就指向谁

我们使用 obj 来调用 test 方法时,指向了 obj,打印 true,而我们将方法赋给 objBind 之后,objBind 来调用时,指向了 objBind

我们来看一下执行 test 方法时,test 上下文:

// obj 调用执行
testContext = {
  AO: {...},
  this: obj,
};
// objBind 调用执行
testContext = {
  AO: {...},
  this: objBind,
}

通过上下文,我们可以清楚的了解到 this 在运行中的指向。

我们来看一下还有一种方式,指向了全局对象。

let test = obj.test;
test(); // false, undefined

这时候执行 test 时的上下文:

testContext = {
  AO: {...},
  this: window
}

作为构造函数下的 this

function Constructor() {
  console.log(this); // "a"对象下创建一个新属性
  this.value = 1;
}

let x = new Constructor();
console.log(x.value); // 1

// {
//   "value": 1
// }

函数调用时,手动设置 this

在这里就要使用到 Function.prototype.applyFunction.prototype.call 了。

在这里也介绍了 applycall 以及 bind,可以看我的这两篇文章 - [《JavaScript 深入之 call 和 apply 函数》]() 与 [《JavaScript 深入之 bind 函数》]()

let obj = {
  value: 1,
};
function fn(a) {
  console.log(this.value);
  console.log(a);
}

fn(2); // undefined, 2
fn.call(obj, 20); // 1, 20
fn.apply(obj, [20]); // 1, 20

多言一句 - 箭头函数指向

箭头函数的 this 指向,不能按照上面的任何一种来。

箭头函数的 this 指向,是在定义时决定的,而不是在调用时决定

var value = 1;
let obj = {
  value: 2,
  test: () => {
    console.log(this); // window 对象
    console.log(this.value); // 1
  },
};
// 按照上面的想法,打印出来的应该是 2,而实际打印的是 1
obj.test();