This指向问题

This指向问题

本文代码尽可能在浏览器环境下运行

面向对象语言中 this 表示当前对象的一个引用。

但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

举个例子:

function fn(){
   console.log(this.x)
}
var obj = {
    x:1,
    f:fn
}
var x = 2
obj.f()
fn()

思考一下,上面的例子 obj.f()fn() 会输出什么

答案是 1 2

在我们预想中,两次调用同一个函数,输出的值肯定是一样的,但是输出的值却不一样,这是因为this的环境不是固定不变的,而是随着执行环境的改变而改变的。

obj.f()的this实在obj对象中的所以输出是1
fn()的this是全局作用下调用的所以输出是2

在学习之前说一句通俗的判断this的指向规则:谁调用,this就指向谁 。下面就这句话实现解释。

直接用习题讲解,不再过多概述含义等。分了6种情况来讲解this指向问题

this的执行环境

1.全局作用域中(浏览器环境)

示例一:

function someFun(a) {
     this.a = a;
}
someFun(5); //函数被调用时,this绑定的是全局对象 window,相当于直接声明了一个全局变量x,并赋值为5
console.log(a);

输出的是 5, 函数被调用时,this绑定的是全局对象 window,相当于直接声明了一个全局变量x,并赋值为5

this.a => window.a

在这里插入图片描述

2.对象中的方法

示例二:

var o = {
    a: 10,
    b: {
        a: 12,
        fn: function () {
            console.log(this.a); // 输出结果是 12
            console.log(this); // 输出结果是 b 对象
        }
    }
}
o.b.fn();

调用时,调用的对象是 o.b 找到 o对象中的b对象,这时调用fn这个方法的对象就是 o.b 所以此时的this执行环境就时b这个对象里面的环境

b: {
      a: 12,
      fn: function () {
          console.log(this.a);
          console.log(this); 
      }
 }

所以自然而然的输出是 12 和 b 这个对象
在这里插入图片描述

示例三:

var o = {
    a: 10,
    b: {
        a: 12,
        fn: function () {
            console.log(this.a); //undefined 若在对象o外定义a,则输出的就是其在外定义的值(全局变量)
            console.log(this);   // window
        }
    }
}
var j = o.b.fn;
j(); 

看上面的例子 j这个变量储存了 o.b对象方法fn,之后调用。这时候的输出就是 undefined 和 window这个对象

还是句话 谁调用,this就指向谁j储存了方法之后调用,在运行环境中有一个window对象(包裹着代码中的变量方法等),这时候fn这个方法就是window这个对象去调用

this.a => 找的是 window下面的 a

this => 则是 window

如果将代码改成以下

var a = 1
var o = {
    a: 10,
    b: {
        a: 12,
        fn: function () {
            console.log(this.a); // 1  全局作用下有一个变量a
            console.log(this);   // window
        }
    }
}
var j = o.b.fn;
j(); 

在这里插入图片描述

示例四:

var point = {
    x: 0,
    y: 0,
    moveTo: function (x, y) {
        this.x = this.x + x;
        this.y = this.y + y;
        console.log(this.x);
        console.log(this.y); 
    }
};
point.moveTo(1, 1)

这个如果看懂了上面的例子 ,很快就能得出答案

还是那句话 谁调用,this就指向谁

point这个对象调用,this就指向point这个对象的内部

所以答案是 1 1 , 调用之后让我们来看看point这个对象的内部

在这里插入图片描述

示例五:

var point = {
    x: 0,
    y: 0,
    moveTo: function (x, y) {
        this.x = x;   //这里就等于改变了point对象里面的x变量
        console.log(this.x); // 1
        console.log(this);   // point对象
        // 内部函数
        var moveX = function (x) {
            this.x = x;  //相当于给全局window定义了一个x并且为1
        };
        // 内部函数
        var moveY = function (y) {
            this.y = y;  //相当于给全局window定义了一个y并且为2
        }
        moveX(x); // 这里是全局调用
        moveY(y);
    }
};
point.moveTo(1, 1);
console.log(point.x); // 1
console.log(point.y); // 0
console.log(x); // 1
console.log(y);// 1

还是那句话 谁调用,this就指向谁

point.moveTo(1, 1) =>this指向point的内部

moveX(x)moveY(y) 其实就相当于 示例一 这个例子,全局调用这两个函数, this指的环境是全局环境

会给 window 这个对象 添加两个变量 x y

在这里插入图片描述

3特殊情况

3.1立即执行函数

示例六:

var a = 10;
var foo = {
    a: 20,
    fn: (function () {
        console.log(this); // window       
        console.log(this.a); // 10
    })()
}
foo.fn

立即执行函数的this指向window

3.2计时器

示例七:

var a = 10;
var oTimer1 = setInterval(function () {
    var a = 20;
    console.log(this.a); // 10
    clearInterval(oTimer1);
}, 100);

计时器的this指向window

示例八:

4显示函数改变this的指向

call、apply、bind (区别上网查找资料,本文暂不分析)

function foo() {
    console.log(this.a);
}
var obj1 = {
    a: 2,
    foo: foo
};

var obj2 = {
    a: 3,
    foo: foo
};
obj1.foo(); //2
obj2.foo(); //3
obj1.foo.call(obj2); //3
obj2.foo.apply(obj1); //2
var bindFn = obj1.foo.bind(obj2)
bindFn()//3

还是那句话 谁调用,this就指向谁

这里的显示函数绑定

obj1.foo.call(obj2) => 将this的指向环境变成了 obj2 输出3

obj2.foo.call(obj1) => 将this的指向环境变成了 obj1 输出2

var bindFn = obj1.foo.bind(obj2) => bind 使用就是 拷贝一个函数给一个新的变量进行调用

5构造函数

示例九:

var name = 'Nicolas';
function Person() {
    this.name = 'Smiley';
    this.sayName = function () {
        console.log(this);
        console.log(this.name);  //Person  Smiley
    };
    setTimeout(this.sayName, 0); //window   Smiley
}

var person = new Person();
person.sayName();

这里我们要小心,这是构造函数内部的this

我粗暴点的说 new 实例化一个对象 this就指向那个实例化对象

实例化这个对象 person 之后, 其内部就包含 构造函数Person的方法属性
在这里插入图片描述

但是万变不离其中 谁调用,this就指向谁

这里会输出两个结果

person Smiley 这个就是person 对象的输出结果 我们能理解

window Smiley 这个则是定时器 setTimeout 输出的结果,可以参考示例七

6箭头函数

示例十:

var obj1 = {
  a: 10,
  b: function() {
    console.log('普通函数:', this)
  }
}

var obj2 = {
  a: 20,
  b: () => {
    console.log('箭头函数:', this)
  }
}

obj1.b();  // 输出 {a:10, b:f} 即 obj1对象
obj2.b();  // 输出 window 对象

箭头函数本身是没有thisarguments 的,在箭头函数中引用 this 实际上调用的是定义上一层作用域的 this,这里强调一下是上一层作用域,因为对象是不能形成独立的作用域。

总结:

​ 1、还是那句话,谁调用,this就指向谁

​ 2、看清楚this是在那种情况下使用的,是构造函数中、还是对象中、又或者是箭头函数。

​ 3、显示函数(call、apply、bind)的区别,本文不够详细可以查阅其他资料。

​ 4、灵活变通处理this指向

以上如有错误欢迎指正,一起学习 LOVE&&PEACE

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值