一、相同点
作用:都是用于改变this
的指向。第一个参数为你要传入的对象,传入后函数的this
就指向了这个对象,后面的参数为你为函数传递的参数值。
二、不同点
/*
* apply()方法
* 当后面参数个数确定用call,参数之间用逗号连接
*/
function.apply(thisObj[, argArray])
/*
* call()方法
* 当后面参数个数不确定时用apply,参数通过数组形式输入
*/
function.call(thisObj[, arg1[, arg2[, [,...argN]]]]);
三、使用示例
- 基本使用
function add(a,b){return a+b};
function sub(a,b){return a-b};
console.log(add.apply(sub,[4,2])); // sub调用add的方法 6
console.log(sub.apply(add, [4,2]));// 2
// call
console.log(add.call(sub, 4, 2)); // 6
- 实现继承
function Animal (name) {
this.name = name;
this.showName = function () {
console.log(this.name);
}
}
function Cat (name) {
Animal.apply(this, [name]);
// call用法
// Animal.call(this, name);
}
let cat = new Cat('mimi')
apply
的一些奇妙用法Math.max
实现获取数组中的最大值:
Math.max
方法不支持数组,但是支持Math.max(p1,p2,p3,...)
, 所以利用apply的特点来解决:max=Math.apply(null, array)
。
这样就轻易的可以得到一个数组中的最大项(apply
会将一个数组转换为一个参数接一个参数的方式传递给方法)。这块在调用的时候第一个参数给了null
,这是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,所以直接传递了一个null
过去。用这种方法同样也可以实现得到数组中的最小项:Math.min.apply(null,array);
。Array.prototype.push()可以实现两个数组合并
同样push
方法没有提供push一个数组,但是它提供了push(param1,param2...paramN)
,同样也可以用apply
来转换一下这个数组,即
var arr1=[1,2,3];
var arr2=[4,5,6];
Array.prototype.push.apply(arr1,arr2); //得到合并后数组的长度,因为push就是返回一个数组的长度
通常在什么情况下,可以使用apply
类似Math.max
等之类的特殊用法:
一般在目标函数只需要n
个参数列表,而不接收一个数组的形式,可以通过apply
的方式巧妙地解决这个问题。
- call方法–验证是否是数组
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
四、手写实现
1.call实现
Function.prototype.myCall = function(context) {
// 1.判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 2.判断 context 是否传入,如果未传入则设置为 window
let context = context || window;
// 3.获取参数
let args = [...arguments].slice(1),
let result = null;
// 4.将调用函数设为对象的方法
context.fn = this;
// 5.调用函数
result = context.fn(...args);
// 6.将属性删除
delete context.fn;
//7.返回结果
return result;
};
2.apply实现
Function.prototype.myapply = function(contex) {
//1.判断是否为函数
if(typeof this !== 'function') {
throw new TypeError("Error");
}
//2.判断传入上下文是否存在
let context = context ? constext : window;
//3.将函数作为上下文的一个属性
context.fn = this;
//4.判断参数是否传入
//5.使用上下文对象来调用这个方法
let result= null;
let args = arguments[1];
if(args) {
result = context.fn(...args);
} else {
result = context.fn();
}
//6.删除新增的属性
delete contex.fn;
//7.返回结果
return result;
}