JS this 指向

JS 里的 this

  • 1、在 function 内部被创建
  • 2、指向调用时所在函数所绑定的对象
  • 3、this 不能被赋值,但可以被 call/apply/bind 改变
this 的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定 this 到底指向谁,实际上 this 的最终指向的是最近调用该 this 所在的函数的对象( this 所在的函数由哪个最近的对象调用,this 就会指向谁),当函数执行时,没有明确的调用对象时,则 this 指向 window
例子1:
function a(){
    var user = "简书";
    console.log(this); // this --> Window
    console.log(this.user); // undefined
}
a();

`按照我们上面说的 this 最终指向的是最近调用该函数的对象,这里的函数 a 实际是被 Window 对象所点出来的,下面的代码就可以证明`

function a(){
    var user = "简书";
    console.log(this); // this --> Window
    console.log(this.user); // undefined
}
window.a();
例子2:
var o = {
    user: "简书",
    fn: function(){
        console.log(this); // this --> o
        console.log(this.user);  // 简书
    }
}
o.fn();

`这里的 this 指向的是对象 o,因为你调用这个 fn 是通过 o.fn() 执行的,那自然指向就是对象 o,
这里再次强调一点,this 的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个`

var o = {
    user: "简书",
    fn: function(){
        console.log(this); // this --> o
        console.log(this.user); // 简书
    }
}
window.o.fn();

`这段代码和上面的那段代码几乎是一样的,但是这里的 this 为什么不是指向 window,如果按照上面的理论,最终 this 指向的是调用该函数的对象,
这里先说个题外话,window 是 js 中的全局对象,我们创建的变量实际上是给 window 添加属性,所以这里可以用 window 点 o 对象`

这里先不解释为什么上面的那段代码 this 为什么没有指向 window,我们再来看一段代码

例子3:
var o = {
    a: 10,
    b: {
        a: 12,
        fn: function(){
            console.log(this); // this --> b
            console.log(this.a); // 12
        }
    }
}
o.b.fn()

`这里同样也是对象 o 点出来的,但是同样 this 并没有指向它,那你肯定会说我一开始说的那些不就都是错误的吗?
其实也不是,只是一开始说的不准确,接下来我将补充一句话,我相信你就可以彻底的理解 this 的指向的问题`
情况1:如果一个函数中有 this,但是它没有被上一级的对象所调用,那么 this 指向的就是 window,这里需要说明的是在 js 的严格版中 this 指向的不是 window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找
情况2:如果一个函数中有 this,这个函数有被上一级的对象所调用,那么 this 指向的就是上一级的对象
情况3:如果一个函数中有 this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this 指向的也只是它上一级的对象,例子3可以证明,如果不相信,那么接下来看例子4
例子4:
var o = {
    a: 10,
    b: {
        // a: 12,
        fn: function(){
            console.log(this); // this --> b
            console.log(this.a); // undefined
        }
    }
}
o.b.fn()

`尽管对象 b 中没有属性 a,这个 this 指向的也是对象 b,因为 this 只会指向它的上一级对象,不管这个对象中有没有 this 要的东西`
例子5:
var o = {
    a: 10,
    b: {
        a: 12,
        fn: function(){
            console.log(this); // this --> window
            console.log(this.a); // undefined
        }
    }
}
var j = o.b.fn;
j();

这里 this 指向的是 window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要

this 永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子5中虽然函数 fn 是被对象 b 所引用,但是在将 fn 赋值给变量 j 的时候并没有执行,所以最终指向的是 window,这和例子4是不一样的,例子4是直接执行了 fn

this 讲来讲去其实就是那么一回事,只不过在不同的情况下指向的会有些不同,上面的总结每个地方都有些小错误,也不能说是错误,而是在不同环境下情况就会有不同,所以我也没有办法一次解释清楚,只能你慢慢地的去体会

再举一个常见的例子,关于事件绑定
例子6:
btn.onclick = function(){
    console.log(this); // this --> btn
}
btn.onclick();
function fn(){
    console.log(this); // this --> obj
}

var obj = {
    show: fn
}

btn.onclick = function(){
    window.setTimeout(function(){
        obj.show();
    }, 100);
}

`自行体会一下,为什么这个 this 指向的是 obj`

科学是严谨的,得出结论之前,我们还是要反复验证,再看一个例子

例子7:
btn.onclick = function(){
    setTimeout(function(){
        console.log(this); // this --> Window
    }, 0);
}
btn.onclick();

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

从例子7代码中看的出来, this 不再函数 btn 的内部,而是在函数 setTimeout 的内部,所以结果没有打印出 btn, 现在我们也不感到奇怪了
你可能还要问,为什么函数 setTimeout 里的 this 指向 window 呢?
这里其实算是一个特例,传入定时器的函数,是由哪个对象调用的?我们不得而知,这种情况,this 就指向 window,以下例子8、例子9同样

例子8:
function m1(){
    function m2(){
        console.log(this); // this --> Window
    }
    m2();
}
m1();
例子9:
var name = "the window";
var object = {
    name: "my object",
    getNameFunc: function(){
        return function(){
            return this.name; // this --> Window
        }
    }
}
console.log(object.getNameFunc()()); // the window
由 this 衍生出的问题

刚才遗留了一个问题没有解决

btn.onclick = function(){
    setTimeout(function(){
        console.log(this); // this --> Window
    }, 0);
}
btn.onclick();

我们期待 this 指向 btn,而 this 现在却指向了 window,这个问题该怎么修复呢? 有很多办法
如果你不知道call、apply、bind,那么恐怕你只能看得懂例子10的方法

例子10:
var name = "the window";
var object = {
    name: "my object",
    getNameFunc: function(){
        var that = this;
        return function(){
            return that.name; // that --> object
        }
    }
}
console.log(object.getNameFunc()()); // my object




btn.onclick = function(){
    var that = this; // 使用变量保存 this,that 变量的值是不会随着环境改变的
    setTimeout(function(){
        console.log(that); // that --> btn
    },0);
}
btn.onclick();
例子11:
btn.onclick = function(){
    var that = this; // 使用变量保存 this
 
    function fn(){  // 将代码写在一个函数 fn 中
        console.log(this); // this --> btn
    }

    setTimeout(function(){
        fn.call(that); // 强行指定 this 为 that 对象
    }, 0);
}
btn.onclick();

/*
  call 方法的作用,是调用函数,同时指定 this 可以代表谁
  例如 fn.call(obj)
  意思就是 调用函数 fn,并且 this 指向 obj 对象
*/
例子12:
btn.onclick = function(){
    var that = this; // 使用变量保存 this
 
    function fn(){  // 将代码写在一个函数 fn 中
        console.log(this); // this --> btn
    }

    setTimeout(function(){
        fn.apply(that); // 使用 apply 方法调用函数,强行指定 this 为 that 对象
    }, 0);
}
btn.onclick();

/*
  apply 方法的作用,是调用函数,同时指定 this 可以代表谁
  例如 fn.apply(obj)
  意思就是 调用函数 fn,并且 this 指向 obj 对象
*/
例子13:
btn.onclick = function(){
    setTimeout(function(){
        console.log(this); // this --> btn
    }.bind(this), 0);
    // 使用 bind 方法,将定时器函数的 this 强行绑定为事件函数的 this
}
btn.onclick();

/*
  bind 方法的作用,是绑定函数的 this,同时返回绑定后的新函数
  例如 
  var fb = fn.bind(obj);
  window.fb();
  无论谁调用 fb 函数, 函数的 this 都会指向 obj
*/
关于自行改变 this 的指向请看JavaScript中call, apply, bind方法的总结,详细的说明了我们如何手动更改 this 的指向

箭头函数版 this

1.如何判断箭头函数的 this

因为箭头函数不具备自己的 this,所以非常简单,假装它不存在,就像这样


箭头函数版this.jpg

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

2. 箭头函数可以用 call 来改变 this 指向吗?

不能!! 试图改变箭头函数的 this 是徒劳的


call改变箭头函数的this.jpg

构造函数版 this

function Fn(){
    this.user = "简书";
}
var a = new Fn();
console.log(a.user); // 简书

这里之所以对象 a 可以点出函数 Fn 里面的 user 是因为 new 关键字可以改变 this 的指向,将这个 this 指向对象 a,为什么我说 a 是对象,因为用了 new 关键字就是创建一个对象实例,我们这里用变量 a 创建了一个 Fn 的实例(相当于复制了一份 Fn 到对象 a 里面),此时仅仅只是创建,并没有执行,而调用这个函数 Fn 的是对象 a,那么 this 指向的自然是对象 a,那么为什么对象 a 中会有 user,因为你已经复制了一份 Fn 函数到对象 a 中,用了 new 关键字就等同于复制了一份

更新一个小问题当 this 碰到 return 时
function fn()  {  
    this.user = '简书';  
    return {};  
}
var a = new fn;  
console.log(a.user); // undefined
function fn()  {  
    this.user = '简书';  
    return function(){};
}
var a = new fn;  
console.log(a.user); // undefined
function fn()  {  
    this.user = '简书';  
    return 1;
}
var a = new fn;  
console.log(a.user); // 简书
function fn()  {  
    this.user = '简书';  
    return undefined;
}
var a = new fn;  
console.log(a.user); // 简书

如果返回值是一个对象,那么 this 指向的就是那个返回的对象,如果返回值不是一个对象那么 this 还是指向函数的实例

function fn()  {  
    this.user = '简书';  
    return undefined;
}
var a = new fn;  
console.log(a); // fn {user: "简书"}

还有一点就是虽然 null 也是对象,但是在这里 this 还是指向那个函数的实例,因为 null 比较特殊

function fn()  {  
    this.user = '简书';  
    return null;
}
var a = new fn;  
console.log(a.user); // 简书

知识点补充:
1.在严格版中的默认的 this 不再是 window,而是 undefined。
2.new 操作符会改变函数 this 的指向问题,虽然我们上面讲解过了,但是并没有深入的讨论这个问题,网上也很少说,所以在这里有必要说一下

function fn(){
   this.num = 1;
}
var a = new fn();
console.log(a.num); // 1

为什么 this 会指向 a?首先 new 关键字会创建一个空的对象,然后会自动调用一个函数 apply 方法,将 this 指向这个空对象,这样的话函数内部的 this 就会被这个空的对象替代

通过 call() 和 apply() 改变函数执行环境的情况下,this 就会指向其他对象

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • 最近有点闲暇时间,就来总结js中this的指向问题,如有不对,请指出。this指向,网上做多的描述是指向那个最终调...
    AlisaMfz阅读 565评论 0 0
  • 1.背景介绍 在javaScript中,this是动态绑定的,它可以是全局对象、当前对象或者任意对象,这完全取决于...
    yaolei72阅读 337评论 0 0
  • 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上...
    Mr__王阅读 730评论 0 3
  • 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上...
    sunnyghx阅读 207评论 1 0
  • 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上...
    web蜗牛阅读 582评论 1 4