js手写bind,apply,call
一.手写bind
// 模拟 bind
Function.prototype.bind1 = function() {
//不知道bind传了多少个参数
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments) //相当于arguments.toArray().slice()
// 获取 this(数组第一项:{x:100}),并改变原数组
const t = args.shift()
// fn1.bind(...) 中的 fn1
const self = this
// 返回一个函数
return function() {
return self.apply(t, args)
}
}
function fn1(a, b, c) {
console.log('this', this)
console.log(a, b, c)
return 'this is fn1'
}
const fn2 = fn1.bind1({ x: 100 }, 10, 20, 30) //bind第一个参数传的是this,后面的参数传递的是真正的函数参数
const res = fn2()
console.log(res)
//上面看不懂看第二种
Function.prototype.myBind = function() {
const obj = arguments[0];
const arr = [];
for (let i = 1; i < arguments.length; i++) {
arr.push(arguments[i]);
}
const self = this;
return function() {
return self.apply(obj, arr);
}
}
function fn1(a, b, c) {
console.log(a, b, c);
console.log('this', this.x);
return 'this is bind'
}
let fn2 = fn1.myBind({ x: 100 }, 10, 20, 30);
let res = fn2();
console.log(res);
二.手写call
Function.prototype.myCall = function() {
var object = arguments[0];
// console.log(arguments[0]);
var arr = [];
for (var i = 1; i < arguments.length; i++) {
arr.push(arguments[i]);//注意循环从i=1开始,把第一个参数去掉
}
object.__proto__.fn = this;//此处运用隐式原型,为了下面能够delete掉
var result = object.fn(...arr); //...扩展运算符将一个数组转为用逗号分隔的参数序列。
delete object.__proto__._fn;
return result;
}
function fn1(a, b, c) {
console.log('this', this)
console.log(a + b + c);
return 'is bind success';
}
let res = fn1.myCall({ x: 100 }, 20, 20, 30);
console.log(res);
三.手写apply
Function.prototype.myApply = function(object, arr) {
object.__proto__._fn = this;
var result = object._fn(...arr);
delete object.__proto__._fn;
return result;
}
function fn1(a, b, c) {
console.log('this', this)
console.log(a + b + c);
return 'is bind success';
}
let res = fn1.myApply({ x: 100 }, [10, 20, 30]);
console.log(res);