zoukankan      html  css  js  c++  java
  • 简述this,call,apply,bind之间的关系

    一、什么是this?

    this是JavaScript语言的一个关键字,它是函数运行时在函数体内部自动生成的一个对象,只能在函数体内部使用。函数的不同使用场合,this的指向不同。

    在ES5中,this永远指向最终调用它的对象。

    例1:
    这里最终调用函数a的对象是全局window,相当于window.a()。
    所以this指向window,this.name的值为全局变量name的值 'windowsName'。
    
    var name = "windowsName";
    function a () {
        var name = "Cherry";
        console.log(this.name); // windowsName
        console.log(this); // [object Window]
    }
    a();
    console.log(this) // [object Window]
    
    
    例2:
    a.fn()调用函数fn的最终对象是a,this指向对象a,所以最终的name值是'skillnull'。
    window.a.fn()调用函数fn的最终对象是a,this指向a,所以最终的name值是'skillnull'。
    注:由于window下的变量和方法访问和调用的时候可以省略window,所以a.fn() === window.a.fn()。
    b()调用函数fn的最终对象是window,this指向window,所以最终的name值是'windowsName'。这里将a.fn赋值给变量b的时候并没有调用fn。  
    
    var name = "windowsName";
    var a = {
        name: "skillnull",
        fn: function () {
            console.log(this.name);
        }
    }
    a.fn();  // skillnull
    window.a.fn(); // skillnull
    
    var b = a.fn;
    b(); // windowsName
    
    

    二、如何改变this的指向?

    • 使用 ES6 的箭头函数
      箭头函数的 this 始终指向函数定义时的 this,而非执行时。
      例3:
      注:若setTimeout推迟执行的函数是某个对象的方法,那么该方法中的this关键字将指向全局环境。
      由此可以看出a.fn2()中被setTimeout推迟执行的函数的最终调用对象是window,this指向window,
      而window中没有fn1方法,所以最终结果为错误信息:this.fn1 is not a function。
      a.fn3()中被setTimeout推迟执行的函数使用了箭头函数,此时的this指向函数定义时的this,即a,所以最终结果为:skillnull。
      a.fn4()中的函数没有被setTimeout推迟执行,最终对象仍为a,此时的this指向a,所以最终结果为:skillnull。
      
      var name = "windowsName";
      var a = {
          name: "skillnull",
          fn1: function () {
              console.log(this.name)
          },
          fn2: function () {
             // console.log(this) // a
              setTimeout(function () {
                  // console.log(this) // [object Window]
                  this.fn1()
              }, 100);
          },
          fn3: function () {
              setTimeout(() => {
                 // console.log(this) // a
                  this.fn1()
              }, 100);
          },
          fn4: function () {
              this.fn1()
          }
      };
      a.fn2() // this.fn1 is not a function
      a.fn3() // skillnull
      a.fn4() // skillnull
    • 在函数内部使用 that = this
      如果上面例子中的fn2中使用that = this改变一下this的指向,此时that属于fn2的内部变量,指向a,所以最终结果为:skillnull
      fn2: function () {
          var that = this;
          setTimeout(function () {
              // console.log(that) // a
              that.fn1()
          }, 100);
      }
    • new 实例化一个对象

      如果函数调用前使用了 new 关键字, 则是调用了构造函数。这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象。

      new实例化一个对象的过程如下:
      1.创建一个空对象 obj;
      2.将新创建的空对象的隐式原型指向其构造函数的显示原型。
      3.使用 call 改变 this 的指向
      4.如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。
      伪代码表示:
      var a = new myFunction("Li", "Yafei");
      new myFunction {
          var obj = {};
          obj.__proto__ = myFunction.prototype;
          var result = myFunction.call(obj, "Li", "Yafei");
          return typeof result === 'obj' ? result : obj;
      }
    • 使用 apply、call、bind
      例4:
      call、apply、bind都可以更改this的指向,三者作用相同。
      由于a.fn赋值给全局变量b的时候没有执行,上面已经说过,此时的this指向widnow,调用b('skill', 'null')的结果为:i am skillnull
      而在调用方法b的时候使用call、apply或bind,将此时的this指向a,所以最终结果是:i am not skillnull
      
      
      var name = 'i am '
      var a = {
          name: "i am not ",
          fn: function (a, b) {
              console.log(this.name + a + b)
          }
      }
      
      var b = a.fn;
      b('skill', 'null') // i am skillnull
      b.call(a, 'skill', 'null') // i am not skillnull
      b.apply(a, ['skill', 'null']) // i am not skillnull
      b.bind(a, 'skill', 'null')() // i am not skillnull

    三、call、apply、bind 和 this 的关系

          从上面的文章可以看出来,其实call、apply、bind最常用的用途是更改this指向。

    四、call、apply、bind三者的区别

           call和apply不同之处主要在于参数的形式,call参数是一个列表,apply参数是一个数组。
           而bind会创建一个新函数,需要手动调用,bind的参数形式和call相同。

    注:如果当前函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象)。

  • 相关阅读:
    病魔带来的礼物
    不可深交者
    做事情
    Maven-7:Maven配置编译的字符集方法
    maven打包可以行文件,包含依赖包等
    Maven打包可执行Jar的几种方法
    maven项目打包时生成dependency-reduced-pom.xml
    【Maven】maven打包生成可执行jar文件
    【Maven学习】Maven打包生成包含所有依赖的jar包
    【Maven学习】Maven打包生成普通jar包、可运行jar包、包含所有依赖的jar包
  • 原文地址:https://www.cnblogs.com/Man-Dream-Necessary/p/9995784.html
Copyright © 2011-2022 走看看