call() 和 apply() 作用类似,call() 和 apply() 方法的区别在于其传递参数的格式不同,一个是参数列表,一个是数组。
func.call(thisArg, arg1, arg2, ...)
func.apply(thisArg, [arg1, arg2, ...])
传递参数并非 call() 和 apply() 真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域,来个栗子
let v1 = {
name: 'xxx'
};
let v2 = {
name: 'bbb'
};
function f(val) {
console.log(this.name, val);
}
f.call(v1, 'v1'); // 输出 xxx v1
f.apply(v2, ['v2']); // 输出 bbb v2
通过传入 对象,使 f() 方法中的this指向了传入的对象,所以最后输出了 name的值。
bind() 方法,这个方法会创建一个函数的实例,其 this 值会被绑定到传递给 bind() 函数的值(也就是第一个参数)。
let v3 = {
name: 'aaa'
};
function f(val) {
console.log(this.name, val);
// console.log(arguments); 可以查看传进来的参数
}
f.bind(v3, 'v3'); // 没有输出
var s = f.bind(v3, 'v3');
s('v33'); // 输出 aaa v3 arguments里面可以查看到传进去的v33
手写call
// 手写call()方法 thisArg 就是要绑定的那个this
Function.prototype.myCall = function(thisArg, ...args) {
// 将 thisArg 转成对象类型(防止它传入的是非对象类型,例如123数字)
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
thisArg.fn = this; // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg.fn(...args);
delete thisArg.fn;
return result; // 执行函数并return其执行结果
}
手写apply
// 手写实现apply方法
Function.prototype.myApply = function(thisArg, args) {
//Symbol只是标记一块内存,不能与其他数据类型进行运算
var fn = Symbol('fn'); // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window; // 若没有传入this, 默认绑定window对象
thisArg[fn] = this; // this指向调用apply的对象,即我们要改变this指向的函数
var newArgs = args ? args : []; // 这里判断是否传递了参数
var result = thisArg[fn](...newArgs); // 执行当前函数(此处说明一下:虽然apply()接收的是一个数组,
// 但在调用原函数时,依然要展开参数数组。可以对照原生apply(),原函数接收到展开的参数数组)
delete thisArg[fn]; // 删除我们声明的fn属性
return result // 返回函数执行结果
}
手写bind
// 手写bind
Function.prototype.myBind = function(...rest1) {
var self = this
var context = rest1.shift() // 取得第一个参数(即执行环境),并删除
return function(...rest2) {
return self.apply(context, [...rest1, ...rest2])
}
}
// 第二种
Function.prototype._call = function(thisArg,...args){
fn = this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
thisArg.fn = fn
let result = thisArg.fn(...args)
delete thisArg.fn
return result
}
// 利用 _call 模拟 bind
Function.prototype._bind = function(thisArg,...args){
let fn = this // 需要调用的那个函数的引用
// bind 需要返回一个函数
return function(){
return fn._call(thisArg, ...args)
}
}