美文网首页
改变this的方法

改变this的方法

作者: 海山城 | 来源:发表于2017-12-07 16:22 被阅读0次

    bind

    bind,在Function.prototype上,返回一个新函数,并且使函数内部的this为传入的第一个参数

    用法

    var name = 'globle'
    var App = {
      name: 'app',
      sayName: function(){
        console.log(this.name)
      }
    }
    
    var obj = {
      name: 'SeaMountC'
    }
    
    App.sayName()                     //"app"
    App.sayName.bind(window)()        //"globle"
    App.sayName.bind(obj)()           //"SeaMountC"
    

    使用场景

    var Page = {
      init: function(){
        this.node = document.body
        this.bind()
      },
      bind: function(){
        this.node.addEventListener('click', function(){
          this.sayHello()//①
        })
      },
      sayHello: function(){
        console.log('hello...' + this.node.innerText)
      }
    }
    Page.init() //报错
    

    上述代码会报错,因为①处的this指的是this.node,而不是我们期待的Page,而document.body中并没有sayHello方法,所以报错。
    修改方法:
    第一种:将this存下来

    var Page = {
      init: function(){
        this.node = document.body
        this.bind()
      },
      bind: function(){
        var _this = this
        this.node.addEventListener('click', function(){
          _this.sayHello() 
        })
      },
      sayHello: function(){
        console.log('hello...' + this.node.innerText)
      }
    }
    Page.init() //"hello...海山城"
    

    参考前一遍写的this的判断方法,_this.sayHello() 相当于Page.sayHello.call(Page),因此sayHello中的this是指Page,没有问题

    第二种:使用bind改变this

    var Page = {
      init: function(){
        this.node = document.body
        this.bind()
      },
      bind: function(){
        this.node.addEventListener('click', function(){
          this.sayHello()
        }.bind(this))
      },
      sayHello: function(){
        console.log('hello...' + this.node.innerText)
      }
    }
    Page.init()
    

    第三种:换种写法,同样使用bind改变this

    var Page = {
      init: function(){
        this.node = document.body
        this.bind()
      },
      bind: function(){
        this.node.addEventListener('click', this.sayHello.bind(this))
      },
      sayHello: function(){
        console.log('hello...' + this.node.innerText)
      }
    }
    Page.init() //"hello...海山城"
    

    注:

    • 注意这种写法,是直接将sayHello作为click事件的回调函数
    • 这种方法如果不bind(this),会报错,因为sayHello中的this指的是document.body,最后就变成document.body.node.innerText

    apply、call

    bind与apply、call相同点:

    • 都是用来改变函数的this对象的指向的;
    • 第一个参数都是this要指向的对象;
    • 都可以利用后续参数传参;

    bind与apply、call区别:

    • bind不会立即调用,其他两个会立即调用
    • 因为bind不会立即调用,因此可以有两种传参形式,
      一种是向call一样fn.bind(context, param1, param2...)()
      另一种是fn.bind(context)(param1, param2...)

    apply与call区别:

    • call方法接收参数列表fn.call(context, param1, param2...),而apply接收参数数组fn.apply(context, paramArray)

    使用事例1
    求和函数,直接arguments.forEach会报错,借用数组的forEach方法,通过call将forEach内部的this从数组改成arguments

    function sum(){
    //   ------------------报错-----------------
    //   arguments.forEach(function(value){
    //     console.log(value)
    //   })
    //   --------------------------------------
      
      var result = 0
      Array.prototype.forEach.call(arguments, function(value){
        console.log(value)
        result += value
      })
      console.log(result)
    }
    sum(9,5,4,3)
    
    • forEach正常调用形式为[1,2,3].forEach(function(val){}),相当于[1,2,3].forEach.call([1,2,3], function(val){}),因此forEach中的this指的是数组本身
    • Array.prototype.forEach(function(val){}),相当于Array.prototype.forEach.call(Array.prototype, function(val){}),这样forEach方法中的this指的是Array.prototype,将第一个参数改成arguments,即可改变forEach方法中的this,相当于此时forEach方法中的代码都是针对arguments处理的
    • 因此[1,2,3].forEach.call([1,2,3], function(val){}),可以写Array.prototype.forEach.call([1,2,3], function(val){})

    使用事例2
    将arguments变成数组,这样就可以使用数组的方法了

    function argsToArray(){
      var args = Array.prototype.slice.call(arguments, 0)
      console.log(args instanceof Array) //true
    }
    argsToArray(1,3,4,5,6)
    

    使用事例3
    借用Math.max(),Math.min()方法,求数组最大,最小值

    var arr = [5, 0, 2, 9]
    //------正常是这么调用的-------------
    //Math.max(5, 0, 2, 9)
    //-------------------------------------------
    
    //使用apply
    Math.max.apply(Math, arr)
    Math.max.apply(null, arr)
    
    • 上面apply的context参数(第一个参数)无所谓是什么,max方法本来就是针对传入的参数做处理的,而不是针对传入的this。
    • apply传入的第二个参数是数组,如果是call的话,就得这样Math.max.call(null, 5, 0, 2, 9)

    相关文章

      网友评论

          本文标题:改变this的方法

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