call、apply 功能介绍

call 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数。
call 和 apply 的区别:传入参数的格式不同,call 正常逐个传入 apply 接受一个参数数组。

注意点:

  • 将 this 绑定为指定对象。
  • 如果传入 null、undefined 将视为传入 window 对象,如果是其他基本类型将其变为对应的包装对象。
  • 执行的函数可以有返回值。
  1. // 用法
  2. var value = 2;
  3. var obj = {
  4. value: 1
  5. }
  6. function bar(name, age) {
  7. console.log(this.value);
  8. return {
  9. value: this.value,
  10. name: name,
  11. age: age
  12. }
  13. }
  14. bar.call(null); // 2
  15. console.log(bar.call2(obj, 'kevin', 18));
  16. // 1
  17. // Object {
  18. // value: 1,
  19. // name: 'kevin',
  20. // age: 18
  21. // }

模拟实现

  1. Function.prototype.call = function (context) {
  2. // 判断是否为 null 或 undefined
  3. if(context === null || context === undefined) {
  4. context = window
  5. } else {
  6. // 将其他基本的数据类型转换为对应的包装对象
  7. context = Object(context)
  8. }
  9. context.fn = this;
  10. var args = [];
  11. // 拿到传入的参数
  12. for(var i = 1, len = arguments.length; i < len; i++) {
  13. args.push('arguments[' + i + ']');
  14. }
  15. // 因为参数是字符串,所以用 eval 执行一下
  16. var result = eval('context.fn(' + args +')');
  17. // 删除不留痕迹
  18. delete context.fn
  19. // 放回函数执行的结果
  20. return result;
  21. }

同样道理 apply 也差不多

  1. Function.prototype.apply = function (context, arr) {
  2. // 判断是否为 null 或 undefined
  3. if(context === null || context === undefined) {
  4. context = window
  5. } else {
  6. // 将其他基本的数据类型转换为对应的包装对象
  7. context = Object(context)
  8. }
  9. context.fn = this;
  10. var result;
  11. // 没有参数直接执行
  12. if (!arr) {
  13. result = context.fn();
  14. }
  15. else {
  16. var args = [];
  17. for (var i = 0, len = arr.length; i < len; i++) {
  18. args.push('arr[' + i + ']');
  19. }
  20. result = eval('context.fn(' + args + ')')
  21. }
  22. delete context.fn
  23. return result;
  24. }

参考:
[1] Javascript 深入之 call 和 apply 的模拟实现。
[2] MDN