call、apply、bind区别


经常看到有使用 callapply,ibnd 这3个方法,每次看到后都会去网上搜一下用法,然而过一段时间就又不会了,归根到底是自己没有理解他的原理,这次准备彻底弄懂,并把自己的理解总结下来。

作用主要有两点:

  • 1、允许为不同的对象分配和调用属于另一个对象的函数/方法,也就是改变(或者说是扩大)函数运行的作用域,优点:对象不需要跟方法有任何耦合关系;
  • 2、提供新的 this 值给当前调用的函数/方法。

call

参数 描述
thisArg 在fun函数运行时指定的this值。
arg1,arg2 指定的参数列表,必须一个一个的列出来

实现步骤:

  1. 判断调用对象是否是函数,定义在函数原型,出现用call等方式调用
  2. 判断传入上下文对象是否存在,如果不存在,则设置window
  3. 处理传参
  4. 函数作为上下文对象的一个属性
  5. 用上下文对象来调用方法,保存结果
  6. 删除新增属性
  7. 返回结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// call函数实现
Function.prototype.myCall = function(context) {
// 判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
// 获取参数
let args = [...arguments].slice(1),
result = null;
// 判断 context 是否传入,如果未传入则设置为 window
context = context || window;
// 将调用函数设为对象的方法
context.fn = this;
// 调用函数
result = context.fn(...args);
// 将属性删除
delete context.fn;
return result;
};

apply

参数 描述
thisArg 在fun函数运行时指定的this值。
arguments 指定的参数数组
  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
  3. 将函数作为上下文对象的一个属性。
  4. 判断参数值是否传入
  5. 使用上下文对象来调用这个方法,并保存返回结果。
  6. 删除刚才新增的属性
  7. 返回结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// apply 函数实现
Function.prototype.myApply = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在,如果未传入则为 window
context = context || window;
// 将函数设为对象的方法
context.fn = this;
// 调用方法
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 将属性删除
delete context.fn;
return result;
};

bind

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 保存当前函数的引用,获取其余传入参数值。
  3. 创建一个函数返回
  4. 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// bind 函数实现
Function.prototype.myBind = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
var args = [...arguments].slice(1),
fn = this;
return function Fn() {
// 根据调用方式,传入不同绑定值
return fn.apply(
this instanceof Fn ? this : context,
args.concat(...arguments)
);
};
};

call()apply 的常见用法

apply 常常被用于数组操作。

1、如合并两个数组,且改变原数组。

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

如求取数组中的最大最小值。

1
2
3
4
5
6
var numbers = [5, 6, 2, 3, 7];  
var max = Math.max.apply(null, numbers);
/* 基本等同于 Math.max(5, 6, 2, 3, 7) */
var min = Math.min.apply(null, numbers);
/* 基本等同于 Math.min(5, 6, 2, 3, 7) */

实现继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person(name, age) {
this.name = name;
this.age = age;
this.showName = function() {
console.log(this.name);
};
this.showAge = function() {
console.log(this.age);
}
}
function Teacher(name, age) {
Person.apply(this, [age,name]);
}
var p1=new Person("李四",25);
var t1 = new Teacher("张三", 30);
t1.showName();//"张三"
t1.showAge();//30

文章作者: 悠然寂夏
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 悠然寂夏 !
评论
评论
评论
  目录