经常看到有使用 call
和 apply
,ibnd
这3个方法,每次看到后都会去网上搜一下用法,然而过一段时间就又不会了,归根到底是自己没有理解他的原理,这次准备彻底弄懂,并把自己的理解总结下来。
作用主要有两点:
- 1、允许为不同的对象分配和调用属于另一个对象的函数/方法,也就是改变(或者说是扩大)函数运行的作用域,优点:对象不需要跟方法有任何耦合关系;
- 2、提供新的
this
值给当前调用的函数/方法。
call
参数 |
描述 |
thisArg |
在fun函数运行时指定的this值。 |
arg1,arg2 |
指定的参数列表,必须一个一个的列出来 |
实现步骤:
- 判断调用对象是否是函数,定义在函数原型,出现用call等方式调用
- 判断传入上下文对象是否存在,如果不存在,则设置window
- 处理传参
- 函数作为上下文对象的一个属性
- 用上下文对象来调用方法,保存结果
- 删除新增属性
- 返回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Function.prototype.myCall = function(context) { if (typeof this !== "function") { console.error("type error"); } let args = [...arguments].slice(1), result = null; context = context || window; context.fn = this; result = context.fn(...args); delete context.fn; return result; };
|
apply
参数 |
描述 |
thisArg |
在fun函数运行时指定的this值。 |
arguments |
指定的参数数组 |
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 将函数作为上下文对象的一个属性。
- 判断参数值是否传入
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性
- 返回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Function.prototype.myApply = function(context) { if (typeof this !== "function") { throw new TypeError("Error"); } let result = null; context = context || window; context.fn = this; if (arguments[1]) { result = context.fn(...arguments[1]); } else { result = context.fn(); } delete context.fn; return result; };
|
bind
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 保存当前函数的引用,获取其余传入参数值。
- 创建一个函数返回
- 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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);
|
如求取数组中的最大最小值。
1 2 3 4 5 6
| var numbers = [5, 6, 2, 3, 7]; var max = Math.max.apply(null, numbers); var min = Math.min.apply(null, numbers);
|
实现继承
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();
|