this的绑定与丢失问题

js中的this绑定与丢失

this指向调用的对象与函数声明的位置无关,只与调用位置有关

this 四种绑定

1、new绑定:new方式是优先级最高的一种调用方式,构造函数只是一些使用new操作符时被调用的函数。
只要使用new方式调用一个构造函数,this一定指向new调用函数新创建的对象。

   function thisTo(a){
        this.a = a;
   }
   var data = new thisTo(2);//在这里进行了new绑定

使用new来调用函数的时候会自动执行下面的操作:
①、创建(或这说构造)一个全新的对象
②、这个新的对象会被执行[[Prototype]]连接
③、这个新对象会绑定到函数调用的this。
④、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

2、显式绑定:显式绑定是通过call()和apply()方法强制制定某些对象对函数进行调用,this则强制指向 调用函数的对象。

  function thisTo(a){
     console.log(this.a);
   }
   var data = {a:2};
   thisTo.call(data);//2

显式绑定中强制绑定---硬绑定(解决隐式绑定丢失问题)

      function foo(a){
        console.log(this.a);
      }
      var obj = {
        a:2
      }
      var bar = function(){
        foo.call(obj);
      };
      bar();//2
      setTimeout(bar,100);//2
      
      bar.call(window);//2

创建了函数bar()并在内部手动调用了foo.call(obj),因此强制把foo的this绑定到了obj上。无论之后如何调用bar,总会手动在obj上调用foo。 硬绑定的典型应用场景就是创建一个包裹函数,负责接收参数并返回值

                     function foo(something){
                        console.log(this.a,something);
                        return this.a + something;
                     }
                     var obj = {
                       a:2
                     };
                     var bar = function(){
                        return foo.apply(obj,arguments);
                     };
                     
                     var b = bar(3);//2 3
                     console.log(b);//5

另一种 使用方法是创建一个可以重复的辅助函数

                     function foo(something){
                        console.log(this.a,something);
                        return this.a + something;
                     }
                     
                     //简单的辅助绑定函数
                     function bind(fn,obj){
                        return function(){
                            fn.call(obj,arguments);
                        };
                     }
                     
                     var obj = {
                        a:2
                     }
                     
                     var bar = bind(foo,obj);
                     var b = bar(3);//2 3
                     console.log(b);//5

由于硬绑定的使用很多,在ES5中提供了内置的方法Function.prototype.bind

                     function foo(something){
                        console.log(this.a,something);
                        return this.a + something;
                     }
                     var bar =foo.bind(obj);
                     var b = bar(3);//2 3
                     console.log(b);//5

bind(...)会返回一个硬编码的新函数,它会把你指定的参数设置为this的上下文并调用原始函数。

3、隐式绑定:指通过为对象添加属性,该属性的值即为要调用的函数,进而使用该对象调用函数

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

4、默认绑定:其他规则无法应用的时候

    function foo (){
        console.log(this.a);
    }
    var a = 2;
    foo();//2
丢失问题

1、隐式丢失:在隐式绑定时,使用了依次引用赋值或者传参操作。丢失之后会使用默认绑定,把this绑定到全局对象或者undefined上,取决于是否是严格模式。

①、引用赋值

        function foo(){
            console.log(this.a);
        }
        var data = {
            a:2,
            foo:foo
        };
        var a = 3;
        var newData = data.foo;
        newData();//3

newData实际上引用的是foo本身,相当于var newData = foo;
data对象作为中间桥,data.foo起传递作用,newData与data没有关系,newData本身没有a属性
newData()输入的是window下的属性a的值。
②、参数传递

        function foo(){
            console.log(this.a);
        }
        
        function doFoo(fn){
            //fn其实引用的是foo
            fn();//调用位置
        }
        var obj = {
            a:2,
            foo:foo
        };
        
        var a = "oops,global";//a是全局对象的属性
        
        doFoo(obj.foo);//oops,global

参数传递其实就是一种隐式赋值,因此我们传入的函数也会被隐式赋值。
如果把函数传入内置的函数中结果是一样的

        function foo(){
            console.log(this.a);
        }
        var obj = {
            a:2,
            foo:foo
        };
        var a = "oops,global";//a是全局对象的属性
        setTimeout(obj.foo,100);//oops,global

回调含糊丢失this绑定是非常常见的。也有可能存在调用回调函数的函数可能会修改this。
在一些流行的JavaScript库中事件处理器常会把回调函数的this强制绑定到触发事件的DOM元素上

2、间接引用:指一个对象的方法引用了另一个对象存在的方法。此时的this指向window或者undefined

        function foo(){
            console.log(this.a);
        }
        var obj = {
            a:2,
            foo:foo
        };
        var newData = {
            a:3
        };
        var a = 4;
        (newData.foo = obj.foo)();//4
        newData.foo();//3

判断使用默认规则不是调用函数位置是否处于严格模式下,而是整个函数体是否处于严格模式,

3、=> 使用词法作用域取代传统的this机制,无法使用上述所说的this的优先级原则
注:=>函数中,根据外层父亲作用域来决定this的指向问题。

        function foo(){
            return (a)=>{
                //this继承自foo()
                console.log(this.a);
            };
        }
        var obj1 = {
            a:2
        };
        var obj2 = {
            a:3
        };
        var bar = foo.call(obj1);  // function (obj1){console.log(obj1.a);}绑定到了obj1上
        bar.call(obj2);//2 不是3!

foo()内部创建的箭头函数会捕获调用foo()时的this,由于foo()的this绑定到obj1上,bar(引用箭头函数)的this
也会绑定到obj1上,箭头函数的绑定无法被修改。(new 也不行!)

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

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,132评论 0 13
  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 6,925评论 15 54
  • 一、你不知道的JavaScript 1、作用域 作用域 LHS RHS RHS查询与简单地查找某个变量的值别无二...
    顶儿响叮当阅读 345评论 0 0
  • 当还是个孩子的时候,因为父母工作的关系。跟自己的姥姥、姥爷一起住。姥姥是特别老派的人,认为女孩子一定要学会做...
    吕苓白阅读 572评论 9 9
  • 屋里空气凝滞,闷热难当,门外雨声好像是另一个世界,没有丝毫的凉意,伸手出去,骤雨疾风。好像被屏蔽了信号一样,门里门...
    江河清湛阅读 200评论 0 8