一、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值会被忽略,但前置参数仍会提供给模拟函数。