JavaScript 中 call、apply、bind 用法和区别

隐私侠
• 阅读 3272

简介

JavaScript 中有三个方法Function.prototype.call()Function.prototype.apply()Function.prototype.bind()可以用来指定函数 this 值。call()apply() 类似,都是调用函数,并指定函数的 this 值thisArg和参数,区别在于call()传入参数是通过参数列表的形式arg1, arg2, ...apply()传入参数是通过数组的形式[arg1, arg2, ...]

function.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, [arg1, arg2, ...])

bind()方法与前两个不同,它创建一个新的函数,在调用新函数时,会调用原函数,并指定原函数的 this 值和参数。bind() 执行的时候并没有调用函数。bind()传入参数的方式和call()一样,都是用参数列表:

fucntion.bind(thisArg, arg1, arg2, ...)

用法

call()

使用call()调用父类构造函数来实现继承,也可以用apply(),只不过传参方式略有区别:

// 使用 call 实现继承
var Pet = function (name, age) {
  this.name = name
  this.age = age
}
var Cat = function (name, age, color) {
  Pet.call(this, name, age)
  this.color = color
}
var cat = new Cat('Garfield', 1, 'orange')
console.log(cat.name)  // Garfield
console.log(cat.age)  // 1
console.log(cat.color)  // orange

// 使用 apply 实现继承:
var Dog = function (name, age, size) {
  Pet.apply(this, [name, age])
  this.size = size
}

当调用一个对象的方法时,方法中 this 指向的是对象本身,用call()改变方法的 this 值:

var utils = {
  setName: function (name) {
    this.name = name
  }
}
// 使用 call 指定 setName 中的 this 指向自己
var Person = function (name) {
  utils.setName.call(this, name)
}
var p = new Person('John')
console.log(p.name)  // 'John'

apply()

apply()方法除了用来指定函数 this 值,还可以用来传递参数。例如,Math.max()允许传入多个参数,求它们的最大值,可以用apply()方法将数组元素作为参数传递给Math.max()方法:

// 使用循环求最大值
var numbers = [1, 0, 0, 8, 6], max = -Infinity
for (var i = 0; i < numbers.length; i++) {
  max = Math.max(numbers[i], max)
}

// 使用 apply 求最大值,代码更简洁
var numbers = [1, 0, 0, 8, 6]
max = Math.max.apply(null, numbers)

// 使用 apply 给数组添加元素
var numbers = [1, 0, 0, 8, 6], arr = []
arr.push.apply(arr, numbers)

另外,因为 JS 引擎有参数长度的限制,如果参数数组太长,可能会造成程序异常。所以,对于超长参数数组,应切分成更小的尺寸,分多次调用该方法。

bind()

在给setTimeoutsetInterval传入函数时,函数中 this 指向的是全局 window 对象。使用bind()方法,重新指定 this 值:

var Person = function (name) {
  this.name = name
}
Person.prototype.say = function () {
  setTimeout(function () {
    console.log('My name is ' + this.name)
  }.bind(this))
}
var p = new Person('John')
p.say()  // My name is John

在给 Dom 对象添加监听函数时,监听函数作为 Dom 对象的一个方法,函数中 this 指向的是 Dom 对象。使用bind()方法,重新指定 this 值,使用箭头函数也可以达到同样的效果:

var fakeDom = { a: 'fakeDom' }
var addEvent = function () {
  this.a = 'addEvent'
  fakeDom.onClick = function () {
    console.log(this.a)
  }
  fakeDom.onClickBind = function () {
    console.log(this.a)
  }.bind(this)
  fakeDom.onClickArrow = () => {
    console.log(this.a)
  }
}
addEvent()
fakeDom.onClick()  // 'fakeDom'
fakeDom.onClickBind()  // 'addEvent'
fakeDom.onClickArrow()  // 'addEvent'

使用bind()绑定参数后,新函数只需要传入剩余参数:

var add = function (a, b) {
  return a + b
}
var add5 = add.bind(null, 5)
console.log(add5(3))  // 8
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Karen110 Karen110
4年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Dax Dax
4年前
JavaScript中call()、apply()、bind()的用法
call()apply()bind()都是用来更改this的指向的其中bind()返回的是一个函数,必须执行才行传参差异:call、bind、apply这三个函数的第一个参数都是this的指向对象,第二个参数差别就来了:call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面obj.myFun.call(db,'
Easter79 Easter79
4年前
sql:mysql:函数:TIMESTAMPDIFF函数实现TimeStamp字段相减,求得时间差
<divclass"htmledit\_views"id"content\_views"<p&nbsp;函数内指定是minute,则最终结果value值的单位是分钟,如果函数内指定为hours,则最终结果value值单位为小时。</p<preclass"has"name"code"<codeclass"hljssql"<
Peter20 Peter20
4年前
mysql中like用法
like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
4年前
JavaScript中call()与apply()有什么区别?
今天读《JavaScript权威指南》时发现其中有段代码用到了apply方法用于递归实现数组的展开。可是我不懂这个函数的用法,因此查了一下,将资料整理如下。Javascript的每个Function对象中有一个apply方法:function.apply(thisObj,argArray)还有一个类似功能的call方法:
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这