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
    
(∩_∩)-----代码改变生活。
原文地址:https://www.cnblogs.com/daixixi/p/9302753.html