美文网首页
this 基本概念

this 基本概念

作者: 南航 | 来源:发表于2017-04-12 16:05 被阅读10次
    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 的 方法吧

    .

    相关文章

      网友评论

          本文标题:this 基本概念

          本文链接:https://www.haomeiwen.com/subject/uaumattx.html