js 之 手打实现 call apply bind
「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
this的常见情况
- 事件中的this是绑定当前事件的元素;
- 自执行函数中的this指向window;
- 定时器回调函数中this指向window;
- 全局作用域的this指向window;
- 方法调用时看方法执行前有没有点,如果有点前面是谁就是谁,没有就是window;
- 箭头函数中的this是箭头函数声明时所在作用域中的this;
- 构造函数中的this指向当前实例;
Function.prototype 上有三个方法 call, apply, bind 供 Function 的实例用来修改函数中的this指向
call的使用
- 语法: 函数名.call(xxx,实参1,实参2,.....)
- 参数: 第一个参数是需要修改的指向this,剩余项是被修改函数实参
- 作用: 把被修改函数的this, 改为call的第一个参数,并传递被修改函数的若干实参,最后让call执行
apply的使用
- 语法: 函数名.apply(xxx,[实参集合])
- 参数: 第一个参数是需要修改的指向this,第二个参数是数组的实参集合
- 作用: 把被修改函数的this, 改为apply的第一个参数,并传入数组的实参集合,最后让apply执行
call与apply的共性都是修改函数的this指向并传递参数让函数执行,区别就是二者的给函数传递实参方式不同,call是一个一个传,apply是传递一个实参集合
function add(a,b,c,d){
console.log(this);
return a+b+c+d
}
let num = add(1,2,3,4); // 10 window
let text = "狗剩";
let num2 = add.call(text,1,2,3,4); // 10 '狗剩'
let ary = [1,2,3,4];
let num3 = add.apply(text,ary); // 10 '狗剩'
bind的使用
- 语法: 函数名.bind(xxx,实参1,实参2,...)
- 参数: 第一个需要修改成的指向this,剩余的是函数需要的若干实参,不可以像apply一样传递实参集合,但是可以不传
- 作用: 把被修改函数的this, 改为bind的第一个参数,并传入若干需要的函数实参,最后返回一个被修改this后的新函数.
bind 与call和apply的区别就是同样修改了 函数的this指向但是 后二者是修改并执行 bind是修改不执行返回新函数需要的时候在执行;
function add(a,b,c,d){
console.log(this);
return a+b+c+d
}
let num = add(1,2,3,4); // 10 window
let text = "狗剩";
let num2 = add.call(text,1,2,3,4); // 10 '狗剩'
let ary = [1,2,3,4];
let num3 = add.apply(text,ary); // 10 '狗剩'
<!--let add2 = add.bind(text);-->
<!--let num4 = add2(1,2,3,4);-->
let add2 = add.bind(text,1,2,3,4);// 如果在bind阶段绑定实参,那么在新函数执行时次传递参数就不会被新函数接收
let num4 = add2();
bind 实现可理化函数
function add(a,b,c){
return a+b+c
}
let num = add(1,2,3);
function add2(a){
return function (b){
return function (c){
return a+b+c
}
}
}
let num2 = add2(1)(2)(3);
let a1 = add.bind(null,1);
let b2 = a1.bind(null,2);
let c3 = b2.bind(null,3);
let d = c3(); // 6
自己实现一下 以上方法
实现 call
Function.prototype.myCall = function (context, ...args) {
context = Object(context) || window;
const key = Symbol();
context[key] = this;
console.log(context, ...args)
console.log(context[key], this)
const fun = context[key](...args);
delete context[key]
return fun
}
console.dir(Function.prototype);
function add(a, b, c) {
console.log(this);
return a + b + c
}
let text = "狗剩";
let num2 = add.myCall(text, 1, 2, 3); // 10 '狗剩'
console.log(num2);
实现 apply
Function.prototype.myApply = function (context, args) {
context = Object(context) || window;
args = args ? args : []
const key = Symbol();
context[key] = this;
const fun = context[key](...args);
delete context[key]
return fun
}
console.dir(Function.prototype);
function add(a, b, c) {
console.log(this);
return a + b + c
}
let text = "狗剩";
let ary = [1, 2, 3];
let num2 = add.myApply(text, ary); // 10 '狗剩'
let num3 = add.myApply(text, 1,2,3); // 10 '狗剩'
console.log(num3);
实现 bind
Function.prototype.myBind = function (context, ...args) {
args = args ? args : []
context = context || window;
const _this = this;
return function newFn(...newArgs) {
if (this instanceof newFn) {
return new _this(...args, ...newArgs)
// new 的时候,this指向new出来的实例,实例的__proto__指向newFn的prototype
// new操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象
// 1、创建一个空的对象
// 2、链接到原型
// 3、绑定this指向,执行构造函数
// 4、确保返回的是对象
}
return _this.myApply(context, [...args, ...newArgs])
}
}
console.dir(Function.prototype);
function add1(a, b, c) {
return a + b + c;
}
let str = "狗剩";
let ary = [1, 2, 3];
let num = add1.myBind(str, 1, 2, 3); // 6 '狗剩'
console.log(num());
转载自:https://juejin.cn/post/7056390478408712222