JS的apply,call和bind
JS
中的apply
,call
和bind
如果你对JavaScript
对象有研究的话你应该知道,在JavaScript
中,函数也是一种对象。那么既然函数也是对象的话,它就存在属于它的方法:call
,apply
, bind
等。这些方法都是为了改变函数运行时的上下文(context)
而存在的,换句话说,就是为了改变函数体内部 this
的指向。JavaScript
的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
1. 区别
1. bind
方法
call
和apply
改变了函数的this
,并且执行了该函数。bind
只是改变了函数的this
,并返回一个函数,但不执行该函数。
1 | var fn = func.bind(window); |
2. apply
,call
的区别
对于 apply
、call
二者而言,作用完全一样,只是接受参数的方式不太一样。apply
接受一个数组作为被调用函数的参数,call
接受不定量的参数作为被调用函数的参数。
1 | func.call(this, arg1, arg2); |
2. JS 原生实现
1. apply
1 | Function.prototype.apply = function(context, arr) { |
2. call
1 | Function.prototype.call = function(context) { |
3. bind
1. 在不考虑构造函数的情况下
1 | Function.prototype.bind = function() { |
2. 在考虑构造函数的情况下
1 | Function.prototype.bind = function(oThis) { |
注意:绑定函数(bind函数返回的新函数)不可以再通过apply和call改变其this指向,即当绑定函数调用apply和call改变其this指向时,并不能达到预期效果。
3. 应用实例
1. 数组之间追加
将数组 array2 拼接到 array1 后边。
1 | Array.prototype.push.apply(array1, array2); |
2. 获取数组中的最大值和最小值
1 | var numbers = [5, 458 , 120 , -215 ]; |
number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。
3. 验证是否是数组
1 | functionisArray(obj){ |
4. 类(伪)数组使用数组方法
1 | var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*")); |
Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。
5. 偏函数
所谓偏函数,就是固定一个函数的一个或者多个参数,返回一个新的函数,这个函数用于接受剩余的参数,
假设我们有一个相加的函数
1 | function add (a, b) { |
而当我们进行多次有规律的计算时:
1 | add(1, 2); |
我们发现,调用 add 方法时,第一个参数相同,但是我们写了5遍,鉴于此种情况,我们可以将 add 方法封装成偏函数的形式来实现更加简洁的代码。
1 | var parAdd = add.bind(null, 1); |
如上代码所示,parAdd 就被成为一个偏函数。
另一种使用偏函数情况是,当我们有一个很通用的函数,为了方便提供一个较常用的变体。举例来说,假设我们有一个函数send(from, to, text),那么使用偏函数可以创建一个从当前用户发送的变体:sendTo(to, text)
6. 实现继承
通过call调用父类构造函数实现继承.
1 | function Person(name, age) { |