this指向_如何讲清楚this指向?

点击“千锋HTML5前端培训”

后台回复【H5】领取IT视频学习教程

ba157b515c9003ddbd690a35eda09d5b.png 不得不说,要搞清楚this是需要一个前提的。 你首先得知道函数、对象、作用域等基本概念, 知道 call、apply、bind方法那再好不过了。 当然学好语文是很重要的,需要知道第一人称和第二人称和第三人称的区别。
6eacce3baa8d1ead4236ec4dd97ed417.png

先来看一个新闻:

“我体内的恶魔已被锁住了这么多年,现在这种锁链已经松了。”
“我很害怕,很孤独,很疑惑,我将要向导致我的痛苦的根源——社会作出反击,我想尽我所能地去伤害这个社会,然后死去。”

这段令人不寒而栗的文字,是美国北达科他州系列杀人案嫌犯约瑟夫·邓肯于2005年5月11日写下的。当人们在近两个月后看到这段文字时,他已经将一个 5口之家的3人残忍地杀害,并绑架了另外2名分别为8岁和9岁的孩子。

假设,你是一个警察,抓到了一个嫌疑犯,然后你在他的家里搜出这本日记,此时你作何感想? 你肯定会想,如果这是嫌疑人自己写的,这不就等于认罪了嘛? 当然,犯罪嫌疑人也可以狡辩说,这日记根本不是我写的,只是我从网上摘抄的段子, 我们试着把日记稍作改动,看看会有什么效果变化。
他体内的恶魔已被锁住了这么多年,现在这种锁链已经松了。他很害怕,很孤独,很疑惑,他将要向导致他的痛苦的根源——社会作出反击,他想尽他所能地去伤害这个社会,然后死去。

注意到了吗?

把第一人称改成了第三人称, 这看上去根本不像日记,更像是一个小说故事。 为什么一个字的改动会有这么大差别呢? 带着对这个问题的思考, 我们来开始今天this指向的学习。 this的英文含义 先看英文解释 this: 这样、这个 接下来看一段代码
var obj = {    show : function(){        console.log(this);    }}obj.show();

结果很容易预测,打印obj对象本身

在JS中,this属于一个关键字,也就是可以理解为,它是一个系统自带命令 通常,我们把它的含义解释为:当前对象 那么问题来了:当前对象到底是指谁呢? 在上面的代码案例中,this代表的就是obj这个对象 接下来我们再看一段代码:
function show(){    console.log(this);}show();
结果打印window对象 如果你对这个打印结果感到奇怪,那么可能你忽略了一个常识问题 window对象是可以省略不写的! 所以,上面的代码,实际上等价于:
function show(){    console.log(this);}window.show();
我再举一个常见的例子,关于事件绑定
btn.onclick = function(){    console.log(this);}btn.onclick();   //手动调用函数//除手动调用外,鼠标单击按钮也可以触发函数执行
最终,无论是手动调用,还是单击按钮调用 打印结果都是btn对象 c3fe4a6370c064df084aa1a205589725.png 我们似乎总结出了一个this指向的规律 this总是指向,调用该函数的对象 如果你的代码结构是这样的
对象.函数();那么,函数里的this,必然指向这个对象本身!
假设这个结论是成立的, 我们不妨来验证一下我们的猜想!!
function show(){    console.log(this);}window.show();  //打印window对象var obj1 = {};obj1.show1 = show;obj1.show1();  //打印obj1对象var obj2 = {};obj2.show2 = obj1.show1;obj2.show2();  //打印obj2对象
从上面代码的例子中,可以看出来 window对象和obj1对象和obj2对象,共享了一个函数 show
window.show == obj1.show1;  //truewindow.show == obj2.show2;  //true
三个对象,用了同一个函数 但打印出的this是各不相同的 window.show(); 打印出window对象 obj1.show1(); 打印出obj1对象 obj2.show2(); 打印出obj2对象 这似乎再一次印证了,我们刚才的猜想: 函数由哪个对象调用,this就指向哪个对象
科学是严谨的,得出结论之前,我们还是要反复验证

再看一个例子:

btn.onclick = function(){    setTimeout(function(){        console.log(this);    },0)}btn.onclick();
实际上,我只是在原来代码的基础上,增加了一个延迟器,并且时间设为0 那么打印出的this会不会有变化呢?? 你可以先思考一番 通常按照直觉,我们会认为,延迟器只是延缓了执行时间,打印结果依然还是btn对象,没有变化 但经过测试发现,实际的打印结果,是 window对象 是我们刚才的猜想错了吗? 要解释这个现象,我们得重新来观察这段代码
btn.onclick = function(){  //    setTimeout(function(){ //        console.log(this);    },0)}btn.onclick();
注意代码当中出现了两个函数,我们分别起名字叫做 函数A函数B 按照我们刚才的猜想: 函数由哪个对象调用,this就指向哪个对象 所以,this指向会依赖它所在的函数 而这个函数,到底是 函数A还是函数B呢? 其实你不难从代码中看的出来, this很明显是在函数B中的 所以, 结果没有打印出 btn, 现在我们也不感到奇怪了 因为, this已经不再函数 A的内部了,而是函数B的内部 你可能还要问,为什么函数B里的 this指向window呢? 这里其实算是一个特例,传入定时器的函数,由哪个对象调用,我们不得而知 这种情况,this就指向window 你暂时记住这个规律就好了,等你学完了作用域链,你就会明白其中的本质 c3fe4a6370c064df084aa1a205589725.png

回到我们开头的新闻

假设日记就是嫌疑人写的。但日记里全是第三人称。那么 『 他 』到底是谁就很难说了 反过来如果日记里用的都是第一人称写的。那么 『 我 』肯定指的是嫌疑人自己 JS函数当中的this关键字, 就相当于我们说话中的第一人称代词我 例如这样一个例子: A对B说:“我要杀了你!” 这里的『我』指代A, 『你』指代B B对A说:”我要弄死你!” 这里的『我』指代B, 『你』指代A 所以你看,同样的一个字,它可以指代任何人,关键看从谁的嘴里说出来
function fn(){    //this, 就相当于中文里的我    //不要上来就问this会指向谁    //我们必须搞清楚上下文环境,fn是谁调用的?(相当于这句话从谁的嘴里说出来)    //如果我们不能弄清楚这个问题,讨论this指向就没有意义    console.log(this);}
c3fe4a6370c064df084aa1a205589725.png

到目前为止,我们差不多可以得出结论了

下面用几个练习最终验证一下

var obj = {    show: function(){        console.log(this);    }}

上面的代码,最终打印obj对象

无论经过多少曲折,我们最终只看一个结论,那就是: this所在的函数,由哪个对象调用? 我把代码进一步改造
function fn(){    console.log(this);}var obj = {    show: fn}btn.onclick = function(){    window.setTimeout(function(){        obj.show();    }, 100);}
上面的代码,最终打印还是obj对象c3fe4a6370c064df084aa1a205589725.png当然了,也总会有一些例外情况, 比如下面这个:
function m1(){    function m2(){        console.log(this);    }    m2();}m1();
我们不禁要问,函数m2是由哪个对象调用的? 我们想尽了各种可能,最终发现都是错的。 我们始终不知道这个m2由哪个对象调用,好像它就那样执行了 而实际的打印结果呢? 不出意外,还是window对象

最后的结论

1. 所有的this关键字,在函数运行时,才能确定它的指向

2. this所在的函数由哪个对象调用,this就会指向谁

3. 当函数执行时,没有明确的调用对象时,则this指向window

由this衍生出的问题

刚才遗留了一个问题没有解决
btn.onclick = function(){    setTimeout(function(){        console.log(this);    },0)}btn.onclick();
我们期待this指向btn,而this现在却指向了window 这个问题该怎么修复呢?有很多办法 如果你不知道call、apply、bind,那么恐怕你只能看得懂方法A
//方法Abtn.onclick = function(){    var self = this; //使用变量保存this,self变量的值是不会随着环境改变的    setTimeout(function(){        console.log(self);    },0)}btn.onclick();
//方法Bbtn.onclick = function(){    var self = this; //使用变量保存this    function fn(){  //将代码写在一个函数fn中        console.log(this);    }    setTimeout(function(){        fn.call(self); //强行指定this为self对象    },0)}btn.onclick();/*  call方法的作用,是调用函数,同时指定this可以代表谁  例如 fn.call(obj)  意思就是 调用函数fn,并且this指向obj对象*/
//方法Cbtn.onclick = function(){    var self = this; //使用变量保存this    function fn(){  //将代码写在一个函数fn中        console.log(this);    }    setTimeout(function(){        fn.apply(self); //使用apply方法调用函数,强行指定this为self对象    },0)}btn.onclick();/*  apply方法的作用,是调用函数,同时指定this可以代表谁  例如 fn.apply(obj)  意思就是 调用函数fn,并且this指向obj对象*/
//方法Dbtn.onclick = function(){    setTimeout(function(){        console.log(this);    }.bind(this), 0 )    //使用bind方法,将定时器函数的this强行绑定为事件函数的this}btn.onclick();/*  bind方法的作用,是绑定函数的this,同时返回绑定后的新函数  例如  var fb = fn.bind(obj);  window.fb();  无论谁调用fb函数, 函数的this都会指向obj*/
c3fe4a6370c064df084aa1a205589725.png
接下来的内容,请学完ES6的箭头函数再来看吧
1. 如何判断箭头函数的this? 因为箭头函数不具备自己的this,所以非常简单,假装它不存在,就像这样:
30b3c82c789bd8be0f94ecfa05944e2b.png

这下this的指向非常清晰了吧

2. 箭头函数可以用call来改变this指向吗? 不能!!试图改变箭头函数的this是徒劳的。
1c312013e4485c6eed1460174f3fca76.png
c3fe4a6370c064df084aa1a205589725.png

最后一个特例:构造函数

1. 什么是构造函数? 假设有一个函数Fn, 我们有两种方式来调用它
  • 普通的调用 Fn()
  • 配合new关键字来调用 new Fn()
第二种调用方式, 函数就变成了构造函数 --------------------------------------- 注意,在构造函数中, 上面我们所讲的结论,是不成立的!! ---------------------------------------

2. 那构造函数里的this是谁呢?

请期待下一篇文章《构造函数与class》

海量精品课资源 扫码添加小千学姐马上领取资源>>> 4be96caa6bcb6290cdf2405e12485b07.png

c445796445ae02293513263e982ebebd.png

▼点击

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值