call() 与 apply() 和 bind()

了解this

如果想用好这几个方法,需要先了解this被调用方式不同而导致值不同的各种情况,然后就会认识到使用这几个方法的原因在哪里。(可以指定this的值)
全局上下文中this指向全局对象,函数上下文this取决于被调用的方式

例:

  • 在非严格模式下,全局调用函数this默认指向全局(window)
var a = 3

function exp(){
  var a = 4
  console.log(this.a)
}

var b = exp()
// 输出3
  • 在严格模式下,因为this为其进入上下文时的值,所以为undefined

function exp(){
 "use strict"
  return this
}

console.log(exp() === undefined)
// 输出 true

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

作为函数被直接调用

上面已经写出了这种情况,值得注意的是,我们往往并不需要this值为window

作为方法被调用

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

var exp =  {
  obj: function context() {
     var text = "hello"
     return this 
  }
}

console.log(exp.obj() === exp)
var a = exp.obj()
console.log(a === exp)

var b = exp.obj
console.log(b() === window) //true,,注意这里当对象的方法被全局调用后this是b的this,则是window

//均输出 true

作为构造函数被调用

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

  1. 创建新对象
  2. 新对象作为this指向的对象
  3. 为新对象添加方法、属性、、并返回对象

需要注意的地方:构造函数返回一个非对象类型时,创建新对象时并不妨碍this的使用,也会返回新创建的对象。但是当构造函数显示返回一个对象时就会将这个对象赋值给变量,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

猜你喜欢

转载自www.cnblogs.com/daixixi/p/9302753.html