call apply bind

244 阅读6分钟

一、call()

定义:使用一个指定的 this值和单独给出的一个或多个参数来调用一个函数。

允许为不同的对象分配和调用属于一个对象的函数/方法。

语法: fun.call(thisArg, arg1, arg2, ...)

参数: thisArg 在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数在非严格模式下运行,则指定为 null 和 undefined 的 this 值会自动指向全局对象(浏览器中就是 window 对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

arg1, arg2, ... 指定的参数列表。

返回值:

使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。

call() 提供新的 this 值给当前调用的函数/方法。你可以使用 call 来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)

1、使用 call 方法调用父构造函数

在一个子构造函数中,你可以通过调用父构造函数的 call 方法来实现继承,类似于 Java 中的写法。下例中,使用 Food 和 Toy 构造函数创建的对象实例都会拥有在 Product 构造函数中添加的 name 属性和 price 属性,但 category 属性是在各自的构造函数中定义的

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

2、类数组转数组

Array.prototype.slice.call(Array_like);
//或者使用字面量(Literals)方式调用
[].slice.call(Array_like)

3、判断数据类型

Object.prototype.toString.call(obj)
//字面量方式调用
"".toString.call(obj)

二、apply()

定义:调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。 语法与call()类似,只是第二个参数是一个数组放置参数。

1、apply() => array改变自身的合并。(concat 是返回一个新的数组)

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

2、=> 判断数组中的最大值

(注:Math.max( ) 返回给定的一组数字中的最大值。如果给定的参数中至少有一个参数无法被转换成数字,则会返回 NaN,如果没有参数,则结果为 - Infinity。)

//方法一
function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}
//方法二
var max = Math.max(...arr);

3、=>使用apply来链接构造器

Function.prototype.construct = function (aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

三、bind()

定义: 创建一个新的函数,在调用时设置this关键字为提供的值。并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。

语法: function.bind(thisArg[, arg1[, arg2[, ...]]])

参数: thisArg 调用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg。

arg1, arg2, ... 当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。 返回值: 返回一个原函数的拷贝,并拥有指定的this值和初始参数。

bind() 函数会创建一个新绑定函数(bound function,BF)。绑定函数是一个exotic function object(怪异函数对象,ECMAScript2015中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数。

使用:

1、创建绑定函数

2、使一个函数拥有预设的初始参数 只要将这些参数(如果有的话)作为bind()的参数写在this后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。

function list() {
  return Array.prototype.slice.call(arguments);
}
// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);

四、Function.prototype.call.bind

var slice = Function.prototype.call.bind(Array.prototype.slice);
slice(arguments);
  • Function.prototype.call是一个引用,用来调用一个函数并且把它的“this”值设置为使用内部提到的方法。
  • 记住“bind”返回一个新的函数,这个函数总是会牢记它的“this”值。因此,.bind(Array.prototype.slice)会返回一个新的函数,它的“this”被永久地设置成了 Array.prototype.slice 函数。

通过结合以上两个,我们现在有了一个新的函数,它将会调用“call”函数并且“this”限定为了“slice”函数。简单地调用slice()便可以引用之前限定的方法。

Call, bind 和 apply 允许我们改变函数被调用的方式,在借用一个函数时经常被使用。大多数开发者都很熟悉借用本地方法,但是很少知道用户定义的方法也可以。Function.prototype.call.bind来借用方法

总结:

call() apply() bind() 都是执行函数的执行上下文‘this’,进行重新的定义(即第一个参数)。

区别在于:

1、call() apply() 直接在该‘this’环境下执行了函数,bind() 是返回一个新的函数,而函数的this指向已经指向了该‘this’环境。

2、call()与apply()的区别在于传参的方式。call() 是对多个参数的罗列,apply是把参数放进一个数组中。 这样就造成参数是数组格式的时候,使用apply更方便些.

比如一个数组要加入其它数组的值。bind()的传参方式和call()一样,不过别忘了他返回的是一个函数,造成这个新函数在执行之前就有参数传入,在执行时传入的参数就排在了bind()传参后面。就有预设参数的妙用。

随着箭头函数的使用,apply,call的使用空间越来越少。

bind绑定函数具有以下内部属性:
[[BoundTargetFunction]] - 包装的函数对象
[[BoundThis]] - 在调用包装函数时始终作为this值传递的值。
[[BoundArguments]] - 列表,在对包装函数做任何调用都会优先用列表元素填充参数列表。
[[Call]] - 执行与此对象关联的代码。通过函数调用表达式调用。
内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数的列表。
当调用绑定函数时,它调用[[BoundTargetFunction]]上的内部方法[[Call]],就像这样Call(boundThis, args)。
其中,boundThis是[[BoundThis]],args是[[BoundArguments]]加上通过函数调用传入的参数列表。
绑定函数也可以使用new运算符构造,它会表现为目标函数已经被构建完毕了似的。提供的this值会被忽略,但前置参数仍会提供给模拟函数。

参考:

JavaScript的借用方法