一、作用
这三个函数能改变函数执行时的上下文,即改变函数运行时的this指向。 setTimeout方法中参数里面的函数是作为回调函数来执行的,回到主栈执行时在全局执行上下文的环境中执行,这个时候的this指向window(即默认绑定)
二、区别
- apply apply接受两个参数,第一个参数是this指向,第二个参数是函数接受的参数,以数组形式传入,改变this指向后原函数会立即执行,且只临时改变this指向一次 第一个参数为null、undefine的时候默认指向window
- call call方法第一个参数也是this指向,后面传入的是一个参数列表,改变this指向后原函数会立即执行,且只临时改变this指向一次 第一个参数为null、undefine的时候默认指向window
- bind 与call类似,第一个参数是this指向,后面传入一个参数列表(但这个参数列表可以分多次传入) 改变this的指向后不会立即执行,而是返回一个永久改变this指向的函数
三者的区别在于:
- 三者都可以传参,但apply是数组,call和bind是参数列表;且apply和call是一次性传入参数,而bind可以分多次传入
- apply、call是立即执行,bind是返回绑定this之后的函数
三、实现
// call实现代码
// 定义一个新的对象,若传入的obj存在,则新对象等于obj, 若obj不存在,则等于window;
// 把this挂在到当前定义的新对象上(this即为调用的函数);
// 第4行代码处理了函数的传参;
// 然后执行创建的新对象的fn函数(即为要调用的函数);
// 最后在执行了以后,把这个挂载的fn删除;
Function.prototype.MyCall = function (...args) {
var newObj = arguments[0] || window;
newObj.fn = this;
var params = [...arguments].slice(1);
var result = newObj.fn(...params);
delete newObj.fn;
return result;
}
function test(...args) {
console.log(this, args);
}
test(123);
test.MyCall({ name: "西瓜" }, 123);
// 1.修改this指向
// 2.动态传递参数
// 3.兼容new关键字
function fn(...args) {
console.log(this, args);
}
let obj = {
name: 'car'
}
// bind的两种调用方式
fn.bind(obj, 111)()
fn.bind(obj, 1)(12)
// bind实现代码
Function.prototype.mybind = function (context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
const args = [...arguments].slice(1),
fn = this;
return function Fn() {
return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments));
}
}