javascript必备知识点之 call、apply、bind 的应用

上文分享了this的应用,这次分享call、apply、bind的应用

1.每个函数都有call、apply、bind方法,通俗点说就是function foo()这样形式就能使用foo.call()/apply()/bind()方法。

2.它们都能改变函数执行上下文。区别在于:

1)call、apply返回值为undefined,且函数立即执行,bind返回值为函数,不会立即执行。

2)call(this,arg2,arg4,arg4…)接收的参数为数据列(通俗点说就是一个一个用逗号隔开的值),apply(this,[a1,a2,a3])接收的第二个参数为数组。

下面通过实例来看运用
定义一个全局变量obj、foo函数,此时foo函数中的this指向window,要访问obj中的属性,需要先访问window,再从window中取值this.obj.name

var obj = {
   name:'hehe',
   age:23
}

function foo(){
   console.log(this.obj.name)    // 'hehe'
}
var obj = {
 name: 'hehe',
 age: '23',
 foo: function () {
   console.log(this.name)    // 'hehe'
 }
}
obj.foo()

上段代码和下段有相似之处:obj都是全局变量,都是访问全局的obj里的name属性。不同的是foo函数里的this指向:上段代码中this指向Window,下段指向obj。

call:
使用call可以改变执行上下文, foo中的this指向obj而不是Window了。

var obj = {
    name:'hehe',
    age:23
}

function foo(){
    console.log(this.name)    // 'hehe'
}

foo.call(obj)

同理原先指向obj的写法,使用call后,可以使this指向其他变量。

var o = {
  name: 'aaaaaaa'
}
var obj = {
  name: 'hehe',
  age: '23',
  foo: function () {
    console.log(this.name)    // 'aaaaaaa'
  }
}
obj.foo.call(o)

对于call第一个参数之后的参数,即为函数可以使用的参数,例如:

var o = {
  name: 'aaaaaaa'
}
var obj = {
  name: 'hehe',
  age: '23',
  foo: function (n, m) {
    console.log(this, n, m)    // { name: 'aaaaaaa' } { a: '4' } '6'
  }
}
obj.foo.call(o, { a: '4' }, '6')

apply改变this的使用和call一毛一样,只是后面的参数为数组:

var o = {
  name: 'aaaaaaa'
}
var obj = {
  name: 'hehe',
  age: '23',
  foo: function (n, m) {
    console.log(this, n, m)    // 同样分别获得值 { name: 'aaaaaaa' } { a: '4' } '6'
  }
}
obj.foo.apply(o, [{ a: '4' }, '6'])

call的应用,例如Object.prototype.toString.call()、Array.prototype.slice.call() //apply

Object和Object.prototype都有toString方法,Object.toString()返回函数"function Object() { [native code] }",Object.prototype.toString()返回类型"[object Object]",那么call在这里充当了什么角色?call改变了toString执行的上下文,Object.prototype.toString()toString this指向Object,Object.prototype.toString.call([]) this就指向[],Object.prototype.toString.call(1) this指向1。那么为什么是使用Object.prototype而不是Array.prototype或者Number.prototype?因为所有对象继承自Object,而Array、Number并不互相包含其他继承对象。

所有的对象都继承自Object,Object.prototype 指向 Object.prototype原型对象,Object.prototype.constructor指向Object。当我们使用arr.toString()时,不能进行复杂数据类型的判断,因为它调用的是Array.prototype.toString,虽然Array也继承自Object,但js在Array.prototype上重写了toString,而我们通过toString.call(arr)实际上是通过原型链调用了Object.prototype.toString。

Array.prototype.slice.call(arguments):slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个新数组。call()方法的第二个参数表示传递给slice的参数即截取数组的起始位置。

function list() {
  return Array.prototype.slice.call(arguments,1); //apply(arguments,[1])
}
var list1 = list(1, 2, 3); // [2, 3]

再来看看bind,bind接收参数形式和call一毛一样(this,arg2,arg3,arg4…)。bind返回的是个函数,但不会立即执行,所以我加了个()执行它。

var o = {
  name: 'aaaaaaa'
}
var obj = {
  name: 'hehe',
  age: '23',
  foo: function (n, m) {
    console.log(this, n, m)   // { name: 'aaaaaaa' } { a: '4' } '6'
  }
}
obj.foo.bind(o, { a: '4' }, '6')()   // 这里执行了bind返回的函数 foo

bind的应用,例如在react中写了一个方法,调用这个方法之前需要将这个方法的this指向绑定到constructor上下文。例如:

constructor(props){
    super(props)
    this.foo = this.foo.bind(this)
}

这样在jsx中调用foo方法this指向组件实例。

不使用bind改变this指向,this的指向就会丢失。例如:

var obj = {
  name: 'hehe',
  age: '23',
  foo: function () {
    console.log(this)   // { name: 'hehe', age: '23', foo: [Function: foo] }
  }
}
obj.foo()
var Fo = obj.foo
Fo()    // window

this指向最终调用它的执行环境。在react中使用bind改变上下文执行环境后,由于react是虚拟DOM结构,所以在div标签中使用onClick事件,this指向的不是DOM而是组件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值