• call() 与 apply() 和 bind()


    this

    如果想用好这几个方法,需要先了解this随调用方式不同而导致指向的对象不同的各种情况,然后了解指定this的几个方法(apply,call,bind)

    一个变量在全局下声明定义(如: 全局作用域下 var a = 3 , 和在全局下或者函数内不使用var声明时都会让变量成为window的一个属性)

    作为函数调用

    • 在非严格模式下,直接调用函数时this默认指向全局(window)
    var a = 3
    console.log(this) // window
    console.log(this.a) //3    这里表明全局变量是window的一个属性
    
    function exp(){
      var a = 4 
      sayHello = "hello world"
      console.log(this.a)
    }
    
    var b = exp()
    // 输出3   函数遵循非严格模式下this为window
    
    this.sayHello // hello world  没有使用var声明的函数变量也是全局变量
    
    • 在严格模式下为undefined
    
    function exp(){
     "use strict"
      return this
    }
    
    console.log(exp() === undefined)
    // 输出 true
    

    下面分析各个调用场合下this的值

    作为方法被调用

    作为方法被调用时,this指向方法调用方法所在的对象上

    var exp =  {
      obj: function context() {
         var text = "hello"
         return this 
      }
    }
    
    console.log(exp.obj() === exp)
    var a = exp.obj()
    console.log(a === exp)
    // 执行后赋值给变量a,此时this指向的是exp
    
    
    var b = exp.obj
    console.log(b() === window) //true,
    // 直接将函数的地址赋值给变量
    
    console.log(b === window.b) // true
    // 而这时的b是一个window属性, 执行b() 相当于window.b(),所以this是window
    
    //均输出 true
    
    // 对象里的方法在任何地方定义均可,只要它作为对象的方法调用this就是这个对象
    var person = {
        var name: "KangKang",
        sayName: function () {
            console.log(this.name)
        }
    }
    
    person.sayName()
    person.sayName({name: "xiaoming"})
    
    //person.sayName() 等价于 person.sayName.call(person)
    
    
    var o = {
      prop: 37,
      f: function() {
        return this.prop;
      }
    };
    
    console.log(o.f()); // logs 37
    // 在对象里面定义的方法
    
    var o = {prop: 37};
    function independent() {
      return this.prop;
    }
    o.f = independent;
    
    console.log(o.f()); // logs 37
    // 在对象外面定义的方法,综合这两个例子可见: 只要作为对象的方法进行调用,那么this就是这个对象
    
    

    作为构造函数被调用

    我们知道构造函数创建一个对象的过程

    1. 创建新对象
    2. 新对象作为this指向的对象
    3. 为新对象添加方法、属性、并返回对象
    function Obj() {
        this.name = "Kangkang"
        return this
    }
    
    var obj = Obj.call({})
    // 创建新对象{} ,新对象 {} 作为this指向的对象
    // 为新对象 {} 添加方法、属性(name = "Kangkang")、并返回对象(return this)
    
    
    // 具有相同功能
    function Obj() {
        this.name = "KangKang"
    }
    
    // 还是成功创建新的对象
    function Obj() {
        this.name = "KangKang"
        return 3
    }
    
    var obj2 = new Obj()
    

    需要注意的地方:构造函数返回一个非对象类型时,不会影响创建的新对象。但是当构造函数显式返回一个对象时就会将这个对象赋值给变量,this的使用则无效。

    function Fn (){
      this.obj = function() {
        return this
      }
    }
    
    let a = new Fn()
    console.log(a.obj() === Fn) // false
    console.log(a.obj() === a) //true
    
    let newObj = {
      name: "小明"
    }
    
    function reObj (){
      this.name = "康康"
      return newObj
    }
    
    let b = new reObj()
    console.log(b.name) //小明,返回的对象是newObj
    
    

    在这么多变化中随时都可能出错,所以call()、apply()、bind()就提供了一个可以指定this的方式

    方法的使用

    1. call()
      这个方法接受多个参数,第一个参数是指定的this值,剩下的都是调用的函数的参数列表
      fn.call(this, arg1, arg2, ...);
      如果第一个参数需要是对象,如果传入了数字、字符串、布尔值的话this会指向该原始值的自动包装对象

      function f(){
            console.log(this)
            console.log(arguments)
        }
        f.call() // window
        f.call({name:'小明'}) // {name: '小明'}, []
        f.call({name:'小红'},1) // {name: '小红'}, [1]
        f.call({name:'康康'},1,2) // {name: '康康'}, [1,2]
      
    2. apply()
      apply() 与call()区别在于第二个参数接受的是一个包含多个参数的数组,对于一些方法需要传入的参数不能是数组
      可以使用apply()调用函数使其可以使用数组作为参数.

    ```
    var a = [1,2,3,4,5,6,7,8,9]
    sum.apply(null,a)
    //将参数a全都传入,它会把参数作为数组传入
    //求数组的最大元素
    Math.max.apply(null,[1,2,6]) // 6
    ```
    
    1. bind()
      bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值.

      this.name = "大牛"
      
      let obj = {
        name: "康康",
        age: 18,
        city:"上海"
      }
      
      let newObj =  {
        name: "小明",
        sayName: function() {
          console.log(this.name)
        }
      }
      
      newObj.sayName()// 小明
      
      let a = newObj.sayName.bind(obj)
      a() //康康
      
      let b = newObj.sayName
      b() //大牛
      
    2. 箭头函数
      这里说一下箭头函数,因为箭头函数没有this,所以会根据作用域链进行寻找this,这也衍生了很多用法,比如在setTimeout里经常出现的上下文(作用域)问题,如果不使用箭头函数,在函数运行时作用域就变成了全局,使用箭头函数会使函数里用到的this绑定在setTimeout的作用域上

      var timer = {
      fn1() {
          setTimeout(function(){
              console.log(this)
          }, 10)
      },
      fn2() {
          setTimeout(()=>{
             console.log(this)
          },20)
      },
      fn3: ()=> {
          setTimeout(()=>{
              console.log(this)
              },30)        
          }
      }
      timer.fn1() //window
      timer.fn2() // timer
      timer.fn3() //window
          
      // 第一个在执行时是在全局调用,相当于 fn1.call(undefined)
      // 第二个使用箭头函数自身没this,使this 指向了timer
      // 第三个自身没this的情况下,外层函数也是箭头函数所以指向了window
      
    (∩_∩)-----代码改变生活。
  • 相关阅读:
    Global.asax的Application_BeginRequest实现url重写无后缀的代码
    Windows 2008驱动安装失败的原因及解决方法
    解决win8.1电脑无法安装手机驱动问题
    适用于Win8的Office2003_SP3精简版集成各类补丁+兼容包
    CSS 文本缩进,行间距
    自动换行后缩进怎么做(CSS)?(可用于 Li y 元素的排版)
    ApkTool反编译和重新打包
    sql server 2005 32位+64位、企业版+标准版、CD+DVD 下载地址大全
    【Lua】Lua中__index与元表(转)
    【VS2012】项目文件夹管理
  • 原文地址:https://www.cnblogs.com/daixixi/p/9302753.html
Copyright © 2020-2023  润新知