JavaScript中的this

MDN|JavaScript this

一、this的指向

1.this是Javascript语言的一个关键字。
它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。

      function test(){
        this.x = 1;
      }

2.理解这句话:

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。

  • 情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window(严格模式下,this指向不是window,是undefined)
function a(){
    var user = "via";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();
  • 情况2:函数有被上一级的对象所调用, 则this指向的就是上一级的对象。
var o = {
    user:"via",
    fn:function(){
        console.log(this.user); //via
    }
}
window.o.fn();
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();
  • 情况3:函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象。
var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();
  • 特殊:
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();
//函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行
//所以最终指向的是window
  • 当this碰到return
    如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
function fn()  
{  
    this.user = 'via';  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined
function fn()  
{  
    this.user = 'via';  
    return 1;
}
var a = new fn;  
console.log(a.user); //via

特殊:虽然null也是对象,但是在这里this还是指向那个函数的实例

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

二、call、apply、bind改变this指向

  • 直接看代码
var a = {
    user:"via",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b(); //undefined
a.fn(); //via
b.call(a);//通过在call方法,给第一个参数添加要把b添加到哪个环境中,this就会指向那个对象。
          //call还可以添加多个参数
b.apply(a);//apply也可以有多个参数,不同的是第二个参数必须是一个数组
  • 如果call和apply的第一个参数写的是null,那么this指向的是window对象
var a = {
   user:"via",
   fn:function(){
       console.log(this); //Window
   }
}
var b = a.fn;
b.call(null);//window
b.apply(null);//window
  • bind方法返回的是一个修改过后的函数。
var a = {
    user:"via",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.bind(a);
//firefox:bound fn()
 length: 0
 name: "bound fn"
 __proto__: function ()
//chrome:ƒ (){
        console.log(this.user);
    }
var a = {
    user:"via",
    fn:function(){
        console.log(this.user); //via
    }
}
var b = a.fn;
var c = b.bind(a);
c();//执行函数
  • 同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的
var a = {
    user:"via",
    fn:function(e,d,f){
        console.log(this.user); //via
        console.log(e,d,f); //10 1 2
    }
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);

二、其他指向

  • 构造函数
    通过这个函数生成一个新对象(object)。这时,this就指这个新对象。
function Fn(){
    this.num = 1;
}
var a = new Fn();
console.log(a.num); //1

//a创建了一个Fn的实例并没有执行
//调用这个函数Fn的是对象a,那么this指向的自然是对象a
  • 存在于一个对象的原型链上,那么this指向的是调用这个方法的对象
var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
  • 作为一个内联事件处理函数
    this指向监听器所在的DOM元素:
<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>
  • 作为一个DOM事件处理函数
    this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。
// 被调用时,将关联的元素变成蓝色
function bluify(e){
  console.log(this === e.currentTarget); // 总是 true

  // 当 currentTarget 和 target 是同一个对象是为 true
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}
  • getter或setter的函数都会把 this 绑定到正在设置或获取属性的对象。
function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, 'sum', {
    get: sum, enumerable: true, configurable: true});

console.log(o.average, o.sum); //  2, 6

三、在匿名函数,定时器中的函数setTimeout/setInterval中

function Person() {  
    this.age = 0;  
    setTimeout((function() {
        console.log(this);
    }), 1000);
}

var p = new Person();//window
  • 匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window
  • 用一个 变量提前把正确的 this引用保存 起来, that = this 或者 ** _this = this** 来保存我们需要的this指针
function Person() {
    var that=this ; 
    that.age = 0;  
    setTimeout((function() {
        console.log(that);
    }).bind(this), 3000);
}

var p = new Person();//1秒后返回构造函数新生成的对象 Person{...}
  • 或用func.bind(this)给回调函数直接绑定宿主对象, bind绑定宿主对象后依然返回这个函数
function Person() {  
    this.age = 0;  
    setTimeout((function() {
        console.log(this);
    }).bind(this), 1000);
}

var p = new Person();//1秒后返回构造函数新生成的对象 Person{...}

四、箭头函数

  • 不绑定this
    箭头功能不会创建自己的this;它使用封闭执行上下文的this值。
  • 在箭头函数中,this是根据当前的词法作用域来决定的,就是说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。在全局作用域中,它会绑定到全局对象上。
    (默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window)
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

注意:如果将thisArg传递给call、bind、或者apply,它将被忽略(thisArg即传入三个函数中的第一个参数)。仍可以为调用添加参数,不过第一个参数应该设置为null。

  • 与普通函数对比
    var obj={  
        num:3,  
        fn:function(){  
            setTimeout(function(){  
                console.log(this.num);  
              //this出现在全局函数setTImeout()中的匿名函数里
             //并没有某个对象进行显示调用,所以this指向window对象 
            });  
        }  
    }  
    obj.fn();//undefined 
    var obj1={  
        num:4,  
        fn:function(){  
            setTimeout(() => {  
                console.log(this.num);  //this指向函数的宿主对象了 
            });  
        }  
    }  
    obj1.fn();//4  
  • 多层嵌套的箭头函数
    var obj1={  
        num:4,  
        fn:function(){  
            var f=() => {    //object,也就是指obj1  
                console.log(this);  
                setTimeout(() => {  
                    console.log(this);//object,也就是指obj1  
                });  
            }  
            f();  
        }  
    }  
    obj1.fn();  

改动一处箭头函数

    var obj1={  
        num:4,  
        fn:function(){  
            var f=function(){      
                console.log(this); 
              //函数f定义后并没有对象调用,this直接绑定到最外层的window对象  
                setTimeout(() => {  
                    console.log(this);
                //外层this绑定到了window,内层也相当于定义在window层(全局环境)  
                });  
            }  
            f();  
        }  
    }  
    obj1.fn();  
    var obj1={  
        num:4,  
        fn:function(){  
            var f=() => {      
                console.log(this); 
               //object,f()定义在obj1对象中,this就指向obj1,这是箭头函数this指向的关键  
                setTimeout(function() {  
                    console.log(this);
                     //window,非箭头函数的情况下还是要看宿主对象是谁
                     //如果没有被对象调用,函数体中的this就绑定的window上  
                });  
            }  
            f();  
        }  
    }  
    obj1.fn();  
  • 1.箭头函数的this绑定看的是this所在的函数定义在哪个对象下,绑定到哪个对象则this就指向哪个对象
  • 2.如果有对象嵌套的情况,则this绑定到最近的一层对象上
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 导语 不得不说,作为一名初级的前端开发者,this关键字这个问题对于我来说一直是一个痛点,什么是this?什么是函...
    Nicole_tiny阅读 528评论 0 4
  • 1.函数调用栈和调用位置 在函数执行的时候,会有一个活动记录(也叫执行上下文)来记录函数的调用顺序,这个就是函数调...
    lightNate阅读 519评论 1 14
  • 作者:yuanzm原文地址:http://segmentfault.com/a/1190000002640298 ...
    IT程序狮阅读 824评论 0 22
  • 不论是面向对象,还是基于对象的语言,都会有this,我更喜欢叫他this指针,如果你不理解指针,认为它是个引用也无...
    faremax阅读 675评论 2 1
  • 当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程、事件驱动、面向对象等一堆词语,但是如果...
    yo_yo_阅读 366评论 0 1