编程技术文章分享与教程

网站首页 > 技术文章 正文

Javascript基础重拾笔记之手写apply、call

hmc789 2024-11-16 20:57:36 技术文章 4 ℃

apply 和 call 的区别

apply 和 call 都能改变函数的 this 指向,区别在于参数的不同,具体用法如下:

var fn = function (args) {
    // do something
};

fn.call(this, arg1, arg2, ...); // call 的第二个参数是一个个的散列参数
fn.apply(this, [arg1, arg2, ...]) // apply 的第二个参数是一个数组

使用场景

比如取数组中的最大值:

var arr = [1, 4, 2, 5, 2, 6];
// 取最大
var max1 = Math.max.call(null, ...arr);
var max2 = Math.max.apply(null, arr);

再比如处理类数组,如 arguments:

var fn = function () {
    var arr = Array.prototype.slice.call(arguments);
    console.log(arr); //[1, 2, 3]
};
fn(1, 2, 3);

apply 和 call 的手写实现

对于apply,实现如下:

// es6 实现方式
Function.prototype.apply = Function.prototype.apply || function(ctx, arr) {
	var context = Object(ctx) || window;
  var fn = Symbol();
  var result;
  context[fn] = this;
  
  if (!arr) {
    result = context[fn]();
  }
  else {
    result = context[fn](...arr);
  }
  delete context[fn];
  return result;
}

// 利用 eval 实现方式

Function.prototype.apply = Function.prototype.apply || function(ctx, arr) {
	var context = Object(ctx) || window;
  var fn = Symbol();
  var result;
  context[fn] = this;
  
  if (!arr) {
    result = context[fn]();
  }
  else {
    var args = [];
    // 转成字符串
    for (var i = 0, len = arr.length; i < len; i++) {
    	args.push('arr[' + i + ']');
    }
    
    // 利用 eval 执行fn
    result = eval('context[fn]('+ args +')');
    
  }
  delete context[fn];
  return result;
}

对于call,实现如下:

// es6 实现
Function.prototype.call = Function.prototype.call || function(ctx, ...args) {
	var context = Object(ctx) || window;
  var fn = Symbol();
  context[fn] = this; // this 就是要执行的函数
  var result;
  result = context[fn](...args);
  delete context[fn];
  return result;
}

// eval 实现
Function.prototype.call = Function.prototype.call || function(ctx) {
	var context = Object(ctx) || window;
  context.fn = this; // this 就是要执行的函数
  var result;
  var agrs = [];
  for (var i = 1,len = arguments.length; i < len; i++) {
  	args.push('arguments[' + i + ']');
  }
  result = eval('context.fn(' + args + ')');
  delete context.fn;
  return result;
}
标签列表
最新留言