关于js中this的指向问题与如何修改this的指向

先上结论:
  1、如果this出现在函数内,那么this永远指向调用这个方法的对象。
  2、如果this不是出现在函数内,即出现在全局作用域或者出现在一个对象内部,那么他永远指向全局对象window。

1、这里先求证结论的第二点
  在全局作用域下,所有的全局变量和方法都是挂载到window这个全局对象下。(一般我们使用a对象的b属性时都是以 a.b 的形式来使用,但是为了书写方便,在使用全局变量和方法时JS允许我们可以省掉window。)
  从下图我们可以看出,在全局作用域下this和window都是同一个东西。

var b = 0;
function f(){
console.log(this);
}
window.b === b; // true
window.f === f // true
this === window // true
1
2
3
4
5
6
7
  我们再来看在全局作用域下的一个自定义对象内部的his指向。

var name = "a";
var obj = {
name: "b",
name1: this.name
}
console.log(obj.name1) // 输出a
1
2
3
4
5
6
  相信大家这里有点疑惑了,欸?不对吧?按道理this不是应该指向obj吗?为什么还是指向window,我们再来看一个。

var name = "a";
var obj = {
name: "b",
obj1: {
name: "c",
name1: this.name
}
}
console.log(obj.obj1.name1) // 输出a
1
2
3
4
5
6
7
8
9
  看到这里大家应该知道了,不管嵌套多少层对象,只要你的this不在一个方法内。你的this始终指向全局对象window。

2、然后求证结论的第一点
  这里有人会提出疑问,这里UP说this永远指向调用这个方法的对象。那么我直接执行这个方法会如何?没有对象调用这个方法时,UP的说法前提都没有,自然是错误的。
  这里大家不要忘了,我之前说了,全局作用域下的方法都是挂载到window对象上的,并且调用全局方法时,可以省略window,所以你直接执性一个方法,其实是window对象在调用这个方法。我们只需要求证直接执方法时方法内部的this与window是不是同一个东西即可证明我的说法是否有错误。
  下面这段代码可以看出我的结论没有错误

function f(){
console.log(this)
console.log(this === window)
}
f() //打印出Window对象,true
1
2
3
4
5
  接下来看这个

var name = "a";
function f(){
console.log(this.name)
}
var obj = {
name: "b",
f: f,
foo: function(){
console.log(this.name);
}
}
obj.f() //打印出b
obj.foo() //打印出b
1
2
3
4
5
6
7
8
9
10
11
12
13
  可以看出来了,此时不管是全局定义的函数还是对象内部定义的函数,它的this始终指向该方法的调用对象。
(我猜上面我说对象内部的this都指向window,有人会举上述类似的例子反驳我说,对象内部方法this指向obj啊,UP真垃圾,关了,看下一篇博文。注意哦,我上面的结论是有前提的,this不在一个方法内,this才指向window。这里如果被我说中,请给点个赞或者评论一下哦!!!感谢)
  我们再来看一个难的。

var name = "a";
var obj = {
name: "b",
foo: function(){
return function(){
console.log(this.name);
}
}
}
// 注意这里foo返回一个方法,要让返回的这个方法执行,必须要再加一个()
obj.foo()(); // 输出a
1
2
3
4
5
6
7
8
9
10
11
  这里又有人疑惑了,不是说好的指向调用的对象obj吗?怎么指向window了。这里注意了,foo方法返回另一个方法,此时obj.foo()已经执行完了,再执行这个函数,相当于在全局直接调用这个方法。此时调用它的还是obj吗?不是,此时执行这个方法的是window。

  此时有人可能会说构造函数里有this,但是在创建对象时构造函数既没有直接执形,也没有被对象调用,而是采用new className()的形式创建对象,那么他里面的this是怎么指向新创建的对象的?

function Animal(name){
this.name = name;
}
var cat = new Animal("cat");
1
2
3
4
  这是因为用new关键字创建对象时,new执行了一些暗操作,其中有一个操作就是修改构造函数this的指向,使this指向新创建的对象。
  new 关键字做了大概如下的暗操作。详细我就不讲了,大家可以看我的博客 js创建对象时new关键字到底做了哪些暗操作? 来了解更多细节。

var obj = {};
// 这里new会显示修改Animal的this指向
Animal.call(obj);
obj.__proto__ = Animal.prototype;
return obj;
1
2
3
4
5
  Animal.call(obj)就是显示修改this指向的操作。这里我简单说下显示修改函数内this指向的几种方式,使其this指向我们想要的对象。
第一种
  Function.prototype.call(thisArg, …args)
    第一个参数是你期望this指向的那个对象,其他参数是你执行这个函数所需的参数
    call方法一旦调用,调用call方法的函数立刻执行。
  Animal.call(obj);
第二种
  Function.prototype.apply(thisArg, [argsArray])
    第一个参数是你期望this指向的那个对象,第二个参数是一个数组,里面是你执行这个函数所需的参数
    apply方法一旦调用,调用apply方法的函数立刻执行。
  Animal.apply(obj);
第三种
  Function.prototype.bind(thisArg, …args)
    第一个参数是你期望this指向的那个对象,其他参数是你执行这个函数所需的参数
    bind方法不会立刻执行,而是拷贝一份这个函数,然后修改this的指向后,最后将这个函数返回出去。
  var copy = Animal.bind(obj);

最后总结之前我再谈一点我的理解
  其实我们可以把我开头总结的两条结论,归为一条,那就是this永远指向调用this所属的方法的那个对象。
  为什么可以这么说呢?因为我觉得全局作用域是一个方法的内部作用域,而调用这个方法的对象正是window,所以全局作用域的this始终指向window,js为了开发书写方便,把这些条条框框都去掉了。

var window = {
f: function(){
// 这里是我们开始书写代码的地方
}
}
window.f();
1
2
3
4
5
6
  所以this的指向问题可以总结为:this永远指向调用this所属的方法的那个对象。
  但是这个不好理解,我也不太确定它内部到底是如何去做的,所以这里只是我的一种猜测。大家还是照我开头那样总结的this指向去解决开发中this的指向问题。

总结:
一、this的指向问题
  1、如果this出现在函数内,那么this永远指向调用这个方法的对象。
  2、如果this不是出现在函数内,即出现在全局作用域或者出现在一个对象内部,那么他永远指向全局对象window。
二、显示修改this指向的方法
  1、call()
  2、apply()
  3、bind()
————————————————
版权声明:本文为CSDN博主「Vgbire」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/RkHker/article/details/104583899

posted @ 2020-03-25 20:08  东东dillon  阅读(522)  评论(0编辑  收藏  举报