this 基本概念

  1. 为什么要使用this
  2. this 的使用误解 ( 2 种 指向误解 )
  3. this 和词法作用域的比较
  4. this 的指向正解
  5. this 的绑定方法( call()、apply()、bind() )

this 总是返回一个对象( fun 也是一个对象 ) + this 指向总是善变的

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

基本概念

this 总是返回一个对象 即包含当前属性或者方法函数的对象, 因为对象的属性和方法函数可以赋予另一个对象,所有 this 指向的对象也是善变的。

  function foo () {
  console.log('name :' + this.name);
  }

  var obj = { name: "obj1", foo: foo };
  var obj2 = { name: "obj2", foo: foo };
  var obj3 = { name: "obj3" };

  obj.foo()   // obj1
  obj2.foo()    // obj2
  1. 为什么 使用this
  • this 提供了一种优雅的方式来 传递 一个对象的引用, 使用 this 能够得到更加 简介的 api.

    显式的传递对象的引用(eg: 函数参数传递) 使得代码变得混乱和难以维护(eg: 传递参数的个数就是个问题)。

  • 使用 this 可以 自动引用合适的上下文环境,并且确定this当前指代的对象进而使用其属性和方法函数

  • ** 我们使用 this 的最终目的是保证能够正确 + 便捷的使用 对象的属性和方法函数处理数据 **

  1. this 的使用误解 ( this 的指向误解 )

    1. this 并不指向函数自身

    2. this 不一定指向定义它的函数作用域或者定义时的作用域

       function foo() {
           var a = 2;
           this.bar = function() {
             console.log(this.a)
           }
         this.bar();
       }
       foo();
      
  2. this 和词法作用域的比较

    this 可以通过 参数传递 或者 直接的对象引用来代替。

    ** 但是 this 因为有其更加灵活的特性才被大家所使用,总是使用词法作用域容易让你 回到编程的舒适区 **

我们来记录 foo 函数被调用的次数

    function foo(num) {
        console.log('foo ' + num);

        // 记录 foo 函数被调用的次数
        this.count++;
    }

    foo.count = 0;
    for(var i = 0; i < 5; i++) {
        foo(i);
    }

    // 记录 foo 函数被调用的次数
    console.log(foo.count);

  分析一下上面的 输出 的值 和 this 的指向?
  若需要你来改造 你应该怎么办??
  1. this 的指向正解 ( 请看 this 的 四种绑定策略 )

    函数内部的this 总是指向 函数本身被调用的位置。(this 绑定规则有详解)

    所以对于 this 的 指向就是 寻找函数的调用位置为首。(浏览器自带的 开发者工具可以很方便的查看函数调用栈)

  2. this 的 三种强制绑定的 方法详解

** javascript 提供了 call apply 和 bind 三个方法,用于固定 this 的指向 **

** call 和 apply bind 都是定义在 Function 上面的方法。**
** call apply 返回一个调用函数的执行结果。 **
** bind 返回一个修改了内部this的 包装函数。 **

  • call 的 传参解析 ( 4 种传参的方式 )

    call 参数使用正常的对象

    call 参数为空、null、undefined 则默认传入全局对象

      var n = 'bar';
      var obj = {n: 'foo'}
    
       function baz() {
         console.log(this.n)
       }
    
       baz.call(obj);        // foo
       baz.call(window);
       baz.call();
       baz.call(null),
       baz.call(undefined);
    

    call 传入一个基本类型的数据,这个基本类型的数据会被转为包装对象 赋值给 this

         var f = function () {
             console.log(this);
         };
    
         f.call(5)     // Number {[[PrimitiveValue]]: 5}
    

    call 可以传递多个参数,第一个参数为需要绑定的对象,后面的参数 依次是函数调用的传参参数

  • apply ( 接受一个数组作为函数执行时的参数 )

  • bind 将函数体内部的 this 强制绑定,返回一个新的经过包装的函数

      // 自己实现的简单功能的 bind 函数
      function bind(fun, obj) {
            return function() {    // 这个 就是 bind 返回的函数
                  fn.apply(obj);
            }
      }
    

apply call bind 使用全攻略 ( 4种使用场景 )

  1. 传递空对象 ** 参数柯里化 **( 看你传递的对象到底有多空 )

    call apply bind 传递一个空对象常常用于参数的柯里化

     function bar(a, b) {
           console.log(a + ',' + b);
     }
    

    直接使用 null / undefined 作为空 传入

     var baz = bar.call(null, 1, 4)      // 1, 4
    
     var bak = bar.bind(null, 10);
     bar(19)    // 10,19
    

    传递进去一个 真空对象 var ø = Object.create(null);

    var baz = bar.call(ø, 1, 4)       // 1, 4
    
  2. 自定义的两种 bind 方法

    1. 创建自定义的 bind 方法函数

       function bindCopy(fn, obj) {
             return function() {
                    fn.apply(obj, arguments);            // 这里主要依赖 call 方法 ** 注意不能少了函数参数 **
              }
       }
      
    2. 扩展函数方法库(** 重要知识点 **)

      Function.prototype.bindCopy() {
             var fn = this;
             var obj = arguments[0];
             var args = Array.prototype.slice(arguments, 1);
             return function() {
                      fn.apply(obj, args)
             }
       }
      

      重要知识点:

      • 函数使用 prototype 可以进行扩展( Function.ptototype.bindCopy )

      • 使用 apply 可以将 类数组对象( 有 length 属性的对象 ) 进行参数结构

      • 函数自身调用时也是使用 this 表示调用的上下文

      • 注意 原函数本身的 参数不能少

  3. apply 和 call 的妙用

    1. 将数组解构 (上面是将类数组对象解构)

      var arr = [1, 4, 6, 7];
      Math.max.apply(null, arr);        // 7
      
    2. 使用 call 方法用在 对象继承中 重新调用被子类覆盖的父类方法;

       function Parent() {
           this.a = 'super';
           this.Super = function() {
                  console.log('父类的 Super 方法' + this. a);      
           }
       }
      
       var p = new Parent();
      
      function Children (a) {
            this.a = a;
            Parent.call(this);     // 调用 父类的构造函数
       }
      
      var c = new Children(12);
      c.Super()          // 使用子类 继承过来的方法
      
      c.Super.call(p)        // 使用 call 重新调用父对象的方法
      

    试着自己实现一个类似 于 forEach 的 方法吧

.

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

推荐阅读更多精彩内容