Appearance
apply、call、bind 实现
在 JavaScript 中我们经常会使用 apply、call、bind 等方法进行函数的调用或者 this 的绑定。
那么它们内部是如何实现的呢?我们可以通过自己实现这些方法来了解它们内部的原理和机制。
接下来我们会实现属于自己的这些方法:hycall、hyapply、hybind。
一. call 方法实现
1.1. hycall 的实现代码
这是一个 JavaScript 函数的扩展方法,它被称为hycall,通过调用该方法可以使得函数被执行,并且可以指定函数中的this上下文对象。
下面是这个函数的实现过程。
javascript
// 给所有的函数添加一个hycall的方法
Function.prototype.hycall = function (thisArg, ...args) {
// 在这里可以去执行调用的那个函数(foo)
// 问题: 得可以获取到是哪一个函数执行了hycall
// 1.获取需要被执行的函数
var fn = this;
// 2.对thisArg转成对象类型(防止它传入的是非对象类型)
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
// 3.调用需要被执行的函数
thisArg.fn = fn;
var result = thisArg.fn(...args);
delete thisArg.fn;
// 4.将最终的结果返回出去
return result;
};
上述代码中:
Function.prototype用来给所有的函数对象添加一个扩展方法 hycall,它的作用是改变函数的上下文对象,使得函数的执行上下文对象可以被指定为 thisArg。
函数的参数可以通过args参数列表传递给被调用函数。
1.2. hycall 的测试代码
接下来我们可以编写一下测试代码:
javascript
function foo() {
console.log("foo函数被执行", this);
}
function sum(num1, num2) {
console.log("sum函数被执行", this, num1, num2);
return num1 + num2;
}
// 系统的函数的call方法
foo.call(undefined);
var result = sum.call({}, 20, 30);
// console.log("系统调用的结果:", result)
// 自己实现的函数的hycall方法
// 默认进行隐式绑定
// foo.hycall({name: "why"})
foo.hycall(undefined);
var result = sum.hycall("abc", 20, 30);
console.log("hycall的调用:", result);
二. apply 方法实现
2.1. hyapply 的实现代码
这是一个 JavaScript 函数的扩展方法,它被称为hyapply,通过调用该方法可以使得函数被执行,并且可以指定函数中的this上下文对象以及函数的参数。
下面是这个函数的实现过程。
javascript
// 自己实现 hyapply
Function.prototype.hyapply = function (thisArg, argArray) {
// 1.获取到要执行的函数
var fn = this;
// 2.处理绑定的 thisArg
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
// 3.执行函数
thisArg.fn = fn;
var result;
// argArray = argArray ? argArray: []
argArray = argArray || [];
result = thisArg.fn(...argArray);
delete thisArg.fn;
// 4.返回结果
return result;
};
上述代码中:
- Function.prototype 用来给所有的函数对象添加一个扩展方法 hyapply,它的作用是改变函数的上下文对象,使得函数的执行上下文对象可以被指定为 thisArg,并且可以将参数列表传递给被调用函数。
2.2. hyapply 的测试代码
javascript
function sum(num1, num2) {
console.log("sum 被调用", this, num1, num2);
return num1 + num2;
}
function foo(num) {
return num;
}
function bar() {
console.log("bar 函数被执行", this);
}
// 系统调用
// var result = sum.apply("abc", 20)
// console.log(result)
// 自己实现的调用
var result = sum.hyapply("abc", [20, 30]);
console.log(result);
var result2 = foo.hyapply("abc", [20]);
console.log(result2);
三. bind 方法实现
2.1. hybind 的实现代码
这是一个 JavaScript 函数的扩展方法,它被称为 hybind,通过调用该方法可以使得函数的上下文对象被永久绑定,并且可以指定函数的参数。
下面是这个函数的实现过程:
javascript
Function.prototype.hybind = function (thisArg, ...argArray) {
// 1.获取到真实需要调用的函数
var fn = this;
// 2.绑定 this
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
function proxyFn(...args) {
// 3.将函数放到 thisArg 中进行调用
thisArg.fn = fn;
// 特殊: 对两个传入的参数进行合并
var finalArgs = [...argArray, ...args];
var result = thisArg.fn(...finalArgs);
delete thisArg.fn;
// 4.返回结果
return result;
}
return proxyFn;
};
上述代码中:
- Function.prototype用来给所有的函数对象添加一个扩展方法 hybind,它的作用是改变函数的上下文对象,使得函数的执行上下文对象可以被永久绑定,并且可以将参数列表传递给被调用函数。
2.2. hybind 的测试代码
javascript
function foo() {
console.log("foo 被执行", this);
return 20;
}
function sum(num1, num2, num3, num4) {
console.log(num1, num2, num3, num4);
}
// 系统的 bind 使用
var bar = foo.bind("abc");
bar();
// var newSum = sum.bind("aaa", 10, 20, 30, 40)
// newSum()
// var newSum = sum.bind("aaa")
// newSum(10, 20, 30, 40)
// var newSum = sum.bind("aaa", 10)
// newSum(20, 30, 40)
// 使用自己定义的 bind
// var bar = foo.hybind("abc")
// var result = bar()
// console.log(result)
var newSum = sum.hybind("abc", 10, 20);
var result = newSum(30, 40);