都是原型上提供的共有属性方法,三个都是改变函数的this指向的方法

call

语法:函数.call([context],[params1],….),传值是一个个的传递
函数基于原型链找到Function.prototype.call这个方法,并且把它执行,在call方法执行的时候完成了一些功能:

  1. 让当前函数执行
  2. 把函数中的THIS指向改为第一个传递给CALL的实参
  3. 把传递给CALL其余的实参,当做参数信息传递给当前函数
  4. 如果执行CALL一个实参都没有传递,非严格模式下是让函数中的THIS指向WINDOW,严格模式下指向的是UNDEFINED
  1. window.name = 'WINDOW';
  2. let obj = {name: 'OBJ'};
  3. function fn(n,m) {
  4. console.log(this.name);
  5. }
  6. fn(10,20); //=>this:window 严格下是undefined
  7. fn.call(obj); //=>this:obj n/m=undefined
  8. fn.call(obj,10,20); //=>this:obj n=10 m=20
  9. fn.call(10,20); //=>this:10 n=20 m=undefined
  10. fn.call(); //=>this:window 严格下是undefined
  11. fn.call(null); //=>this:window 严格下是null(第一个参数传递的是null/undefined/
  12. 不传,非严格模式下this指向window,严格模式下传递的是谁this就是谁,不传thisundefined

重写call方法

  1. ~ function () {
  2. /*
  3. * call:改变函数中的THIS指向
  4. * @params
  5. * context 可以不传递,传递必须是引用类型值(因为后面要给它加$fn的属性)
  6. */
  7. function call(context) {
  8. //this:sum 也就是当前要操作的这个函数实例
  9. context = context || window;
  10. let args = [], //=>除第一个参数外剩余传递的信息值
  11. result;
  12. for (let i = 1; i < arguments.length; i++) {
  13. args.push(arguments[i]);
  14. }
  15. context.$fn = this;
  16. result = context.$fn(...args); //=>args=[10,20] ...是ES6中的展开运算符,把数组中的每一项分别的展开传递给函数 //=>context.$fn(10,20)
  17. delete context.$fn;
  18. return result;
  19. }
  20. /* 扩展到内置类的原型上 */
  21. Function.prototype.call = call;
  22. }();

apply

语法:函数.call([context],[a,b,c…]),传值是以数组的形式传的,其他的与call方法相同

bind

用法同call/bind相同,区别于他们的是,bind不是立即执行this,而是预先改变this

  1. let obj={name:'OBJ'};
  2. function fn(){
  3. console.log(this.name);
  4. }
  5. document.body.onclick=fn; //=>当事件触发,fn中的this:BODY
  6. //=>点击BODY,让FN中的THIS指向OBJ
  7. //document.body.onclick=fn.call(obj); //=>基于call/apply这样处理,不是把fn绑定给事件,而是把fn
  8. 执行后的结果绑定给事件
  9. document.body.onclick=function(){
  10. //this:BODY
  11. fn.call(obj);
  12. }
  13. document.body.onclick=fn.bind(obj); //=>bind的好处是:通过bind方法只是预先把fn中的this修改为obj
  14. ,此时fn并没有执行呢,当点击事件触发才会执行fncall/apply都是改变this的同时立即把方法执行) =>在IE6~8中不支持bind方法 预先做啥事情的思想被称为“柯理化函数”