手写bind
你应该知道 bind/apply/call 的区别哈,那你能手写一个 bind 么? 我:wtf。。。。
bind
- bind 方法会创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数(是的, bind 是有多个参数,只是我们平时只用一个)将作为新函数的预置参数,供调用时使用。
原版使用
javascript
// 浏览器环境
var a = 2;
function fn() {
let a = 1;
console.log(this.a);
console.log(arguments);
}
let obj = {
a: 3
};
const _fn = fn.bind(obj, [4, 5]);
_fn(6, 7); // 3 [[4,5],6,7]
fn(); // 2 undefined
手写一个 bind
js
Function.prototype.myBind = function (context) {
let fn = this; // 保存 this 即当前调用的 fn
// arguments 是一个独立的对象, 虽然长得像数组但他不是数组。 这里提供2种方式
// 1.通过 call 取值
// let args = Array.prototype.slice.call(arguments, 1); // 提取参数
// 2.转为数组
let params = Array.from(arguments).slice(1);
// 当然也可以在定义函数时 使用 function (context,...args) {}
// args = args ?? [];
// 这里建议不写死参数 。因为无法判断 目标函数到底有多少参数
return function () {
// if (this instanceof newFn) {
// return new fn(...arguments, ...params);
// }
return fn.apply(context, [...params, ...arguments]);
};
};
// 测试
var a = 2;
function fn() {
let a = 1;
console.log(this.a);
console.log(...arguments);
}
let obj = {
a: 3,
};
const _fn = fn.myBind(obj, [4, 5]);
_fn(6, 7, 8, 9); // 3 [ 4, 5 ] 6 7 8 9
let fn2 = {
fn: function fn() {
let a = 1;
console.log(this.a);
console.log(...arguments);
},
};
const _fn2 = fn2.fn.bind(obj, [4, 5]);
_fn2(6, 7, 8, 9); // // 3 [ 4, 5 ] 6 7 8 9
那 call / apply 呢?
js
// 注意是2个参数。 不能用 ...args
Function.prototype.myApply = function (context, args) {
let fn = this;
context['fn'] = fn;
args = args ?? [];
const res = context.fn(...args);
return res;
};
// 一摸一样 就改了下参数
Function.prototype.myCall = function (context, ...args) {
let fn = this;
context['fn'] = fn;
args = args ?? [];
const res = context.fn(...args);
return res;
};
var a = 2;
function fn() {
let a = 1;
return { a: this.a, args: arguments };
}
let obj = {
a: 3,
};
console.log('my apply:', fn.myApply(obj, [1, 2, 3]));
console.log('origin apply:', fn.apply(obj, [1, 2, 3]));
// my apply: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }
// origin apply: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }
// ---
console.log('my call:', fn.myCall(obj, 1, 2, 3));
console.log('origin call:', fn.call(obj, 1, 2, 3));
// my call: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }
// origin call: { a: 3, args: [Arguments] { '0': 1, '1': 2, '2': 3 } }