js实现call和bind

js实现call和bind

call ,apply 和 bind 都可以强制更改函数中的this指向,语法:
call: call(context, param1,param2,…)
apply:apply(context, [param1,param2, …])
bind:bind(context, param1,param2,…)
这三个函数中的第一个参数 context 就是自己决定函数中的this的指向,其余参数就是传给函数的实参

call、apply、bind的区别

call和apply在改变函数中this的执行时候会立即执行函数

function fn(){
    console.log(this)
 }
 let obj = {};
 fn.call(obj);  // obj
 fn.apply(obj);  // obj

bind只是先改变了函数中的this指向,并不会立即执行函数,如果需要执行函数,需要另行调用

function fn(){
    console.log(this)
 }
 let obj = {};
fn.bind(obj);  // 这里没有输出
fn.bind(obj)();  // obj 

call源码及关于call的题目

  • call源码
Function.prototype.call = function(context, ...param) {
  context = context == null? window: context;
  if(typeof context != 'object' || typeof context != 'function'){
    context = Object(context);
  }
  context.$fn = this;
  let res = context.$fn(...param);
  delete context.$fn;
  return res;
  • call相关题目
var name = "测试";
function A(x,y) {
  var res = x + y;
  console.log(res, this.name);
}
function B(x, y) {
  var res = x - y;
  console.log(res, this.name);
}
B.call(A,40, 30); 
// this-> B; context -> A
// context.$fn = this;  context.$fn(40,30);
// => A.$fn = B;  A.$fn(40,30);  执行B这个函数,只是函数中的this是A
B.call.call.call(A, 20,10);
// this: B.call.call;  context: A
// context.$fn = this  => A.$fn = B.call.call;
// context.$fn(20,10);  => B.call.call(20,10);  只是这个执行,函数中的this是A,而不是B.call
// =>this: A;  context: 20
// context.$fn = this; => 20.$fn = A
// context.$fn(10);  => 20.$fn(10); 效果等价于 A.call(20,10);
// 执行的是A,函数中的this是20,传递的参数是 【10】
// => NaN  undefined
Function.prototype.call(A, 60, 50);
// this: Function.prototype;  context: A
// context.$fn = this;  => A.$fn = Function.prototype;  
// context.$fn(60,50); => Function.prototype(60,50) 这个函数执行,只是函数中的this的A,而不是 Function
// 由于Function.prototype是一个匿名空函数,所以不会有任何输出
// =>没有任何输出
Function.prototype.call.call.call(A, 80,70);
// this: Funtion.prototype.call.call; context: A
// context.$fn = this; => A.$fn = Function.prototype.call.call
// context.$fn(80,70); => Function.prototype.call.call(80,70); 这个函数执行,只是函数中的this是A,而不是 Function.prototype.call
// this: A;  context: 80
// context.$fn = this;  => 80.$fn = A;
// context.$fn(70);  =>A.$fn(70); 效果等价于 A.call(80, 70)
// 执行的是A,函数中的this是80,传递的参数是 【70】
// => NaN  undefined
 // 变式训练
  function fn1(){
   console.log(1)
 }
 function fn2() {
   console.log(2)
 }
 fn1.call(fn2); // 1
 fn1.call.call.call(fn2); 
 // this: fn1.call.call;  context: fn2;
 // fn2.$fn = this;  => fn2.$fn = fn1.call.call
 // fn2.$fn(); => fn1.call.call();  执行这个函数,只是函数中的this是fn2,而不是 fn1.call
 // this: fn2;  context: window
 // context.$fn = this;  => window.$fn = fn2
 // context.$fn();  => window.$fn();  等价于 fn2.call()
 // => 2
 Function.prototype.call(fn2);
 // fn2.$fn = Function.prototype;
 // fn2.$fn(); => Function.prototype() 匿名空函数执行,没有输出
 Function.prototype.call.call.call(fn2);
 // fn2.$fn = Function.prototype.call.call
 // fn2.$fn();  => Function.prototype.call.call()  函数中的this的fn2
 // window.$fn = fn2;
 // window.$fn();  => fn2();
 // => 2
 */

bind 源码

  • 问题引申
var obj = {name: 'obj'};
function fn(){
  console.log(this);
}
// 想要实现点击时,触发函数,输出的是obj, 而不是当前元素
// document.body.onclick = fn; // 这样显然不行

// document.body.onclick = function(){  // 这样也不行
//   fn(); // window
// }

// document.body.onclick = function(){
//   fn.call(obj);  // 可行, 由此推测出bind的源码
// }
  • bind 源码
(function(){
  function bind(context, ...param){
    // this: 当前要操作的函数
    context = context == null ? window: context;
    let that = this;
    return function(...arg){
      let args = param.concat(arg)
      that.call(context, ...args);
    }
  }
  Function.prototype.bind = bind;
})();

document.body.onclick = fn.bind(obj); // obj
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值