this的绑定规则(四种)

  1. this 的四种绑定策略( 默认绑定、隐式绑定、显式绑定、new 绑定 )

     默认绑定:this 一般默认指向全局作用域
     隐式绑定:使用对象调用函数进行绑定( obj.fun() )  * 隐式绑定可能丢失 *
     显示绑定:使用 apply call bind 进行强制绑定
     new 绑定: 将 this 绑定到对象实例
    
  2. this 绑定的优先级别

     this 的三篇文章按照顺序复习
     this基本概念 -> this绑定规则 -> this 应用实例
    

包含 this 的函数 的 调用位置决定了 内部 this 的指向对象, 所以 确定 this 的指向就是寻找包含 this 的函数的调用位置

寻找函数的调用栈和调用位置( 浏览器的开发者工具 )

this 的 四种绑定策略

默认绑定策略

  1. this 默认指向全局对象

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

** 严格模式 ”use strict“ ( 无论是函数内部严格模式或者是整体文件严格模式 ) 不能将全局对象用于默认绑定,this 将会绑定到 undefined 上 **

隐式绑定( 对象调用的绑定 )隐式绑定可能 丢失

  1. 隐式绑定会把函数中的 this 绑定到这个 调用的 上下文环境中

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

作为 foo 函数的调用对象 baz 成为 this 的上下文对象( 这样描述不是很恰当 )

  1. 隐式绑定的 this 丢失的 两种情况

主动赋值丢失 ( 本质相当于为函数起了 别名 )

函数传参(将函数作为参数)丢失( 回调函数丢失 ) 函数传参也是一种隐式的赋值操作

  • 主动赋值丢失

    主动赋值丢失本质是将 函数的引用暴露在全局作用域下
    
        function foo() {
            console.log(this.a);
        }
        var baz = {
            a: 2,
            foo: foo
        }
        var bar = baz.foo;    // 主动赋值 ** 不是主动执行 ** (只是地址的一次 引用)
        bar();       // 输出 undefined 或者 window
    
  • 函数传参丢失( 将函数作为参数传递 也是一次引擎的右查询 )
    ** 回调函数本质也是将函数作为参数传递,是一次隐式的赋值操作 **

      function foo() {
        console.log(this.a);
      }
      var baz = {
        a: 2,
        foo: foo
      }
    
      var bar = baz.foo;      // 这里其实不是绑定,只是一次 地址的引用( 函数也是一个对象 )
      setTimeout(bar, 100);       // 函数传参 回调函数 丢失绑定
               // 输出 undefined 或者 window
    
  • 主动赋值操作 是因为进行了 函数地址的引用, 将函数的 上下文环境改变了
    ** 区别于函数的调用执行 **

显示绑定 和 硬绑定策略

使用call 和 apply 可以强制改变 this 的指向

但是看看下面这种情况

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

  var jon = {
    a: 1,
    foo: foo
  }

  var bar = baz.foo;
  bar.call(baz);    // 2
  bar.call(jon);     // 1

这 bar 函数内部的 this 指向 好像更改的很随意呀

我们看看怎样使得其 能从一而终的指向 呢??( 找一个内部没有 this 的函数试试 )

function foo() {
    console.log(this.a);
}
var baz = {
    a: 2,
    foo: foo
}
var jon = {
    a: 1,
    foo: foo
}
var bar = function() {
    foo.call(baz);
};
bar();        // 2
bar.call(baz)    // 2
bar.call(jon);    // 2

这次函数 foo 内部 的 this指向就从一而终了
** 硬绑定的策略是一旦绑定this, this 的指向不再修改。( 和显示绑定不同 ) **
重点: 我们使用了一个包装函数 负责函数的指向设置

硬绑定策略

  1. 创建一个包裹函数 负责接收参数并返回值

       function something(something) {
         console.log(this.a, something);
         return this.a = something;
       }
    
       function bind(fun, obj){
         return function (arg) {
             return fun.call(obj, arg);
         }
       }
    
       var obj = {
         a: 2
       }
    
       var bar = bind(something, obj);
    
       bar(3);      // 2 3
       var b = bar(3);    // 3 3
       console.log(b);    // 3
    

硬绑定策略就是一旦为函数绑定了内部 this 的指向对象,这个指向对象便不再会被改变( 当然对象中的值是可以更改的 )

  1. es5 提供了 内置的硬绑定方法 Function.prototype.bind

       function foo(something) {
           console.log(this.a, something);
           return this.a + something;
       }
       var baa = {
           a: 2
       }
       var bar = foo.bind(baa);
       var bb = bar(3);    // 2 3
       console.log(bb);     // 5
    
  2. API 调用的上下文( 内置函数或者第三方库 中提供 硬绑定 this指向的解决方案 )

许多JavaScript 内置的函数或者第三方库函数能够提供一个绑定上下文环境的 可选参数( 使用权在开发人员手中 ),

称其为上下文( context ),作用和 bind 一样,或者其内部就是使用 bind 实现的

方便你的代码实现( 让你少些一些代码 )

    // forEach 
    var arr = [1, 3, 5, 6, 7];
    var obj = {
      id: "qwe"
    }

    arr.forEach(function(item){
      console.log(item, this.id)
    }, obj)    //  这里的 obj 就是显示绑定上下文的 对象
news 绑定策略

使用 new 调用函数,或者 函数构造时会发生 this 的绑定行为

详见对象的构造函数一章

四种绑定策略的优先级

  1. new 构造函数调用和 bind 硬绑定策略的优先级比较

     function foo(something) {
       this.a = something;
     }
    
     var obj = {}
    
     var bar = foo.bind(obj)
     bar(2);
    
     console.log(obj.a);      // 2
    
     var baz = new bar(3);
     console.log(baz.a);    // 3
     console.log(obj.a);    // 2
    

分析结果: new 绑定策略似乎是和 bind 绑定策略 互相不干扰的? 真的是吗??

  1. 查阅函数原型链可知

    1. new 构造函数调用时会产生新的 原型对象保证 this 的指向
    2. *** new 构造函数的原型链中并没有 硬绑定策略绑定的 this 指向对象***
  2. 根据 MDN bind 函数的实现方式来看

    new 绑定策略和 bind 一同使用时,若硬绑定的函数被new 调用,就会 ** 使用 new 新创建的 this 替换 硬绑定策略的 this **

  3. bind 绑定 和 new 绑定策略 共同使用 到底想干什么??

    请看下一节 中的 ** 奇怪的绑定对象却有巧妙的用法 **

5 . this 的绑定策略优先级 现在自己猜猜看

.

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

推荐阅读更多精彩内容