手写callapplybind函数和arguments&数组函数slice的实现

Posted 忘忘碎斌bin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写callapplybind函数和arguments&数组函数slice的实现相关的知识,希望对你有一定的参考价值。

手写call、apply、bind函数

手写call函数

Function.prototype.msicall = function (thisArg, ...args) {
  //因为调用此方法是通过,函数对象调用的,那么这个函数内的this就是这个函数对象
  var fn = this;
  // 边界判断,系统call函数在调用的时候忽略显示绑定情况
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
  // 通过对象调用,使this绑定到传入要绑定的对象
  thisArg.fn = fn;
  // 调用函数,其实内部的this会存在fn这个函数,因为this指向的对像上是手动挂载上去的源函数
  var result = thisArg.fn(...args);
  // 删除挂载的函数
  delete thisArg.fn;
  // 返回值
  return result;
};

手写apply函数

// 采用默认值,因为如果没有参数只有绑定对象,那么默认args就是undefined
// undefined在解构时会报错
Function.prototype.msiapply = function (thisArg, args = []) {
  var fn = this;
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
  thisArg.fn = fn;
  var result = thisArg.fn(...args);
  delete thisArg.fn;
  return result;
};

手写bind函数

Function.prototype.msibind = function (thisArg, ...args) {
  var fn = this;
  // edge case 边界判断
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
  return function (...params) {
    thisArg.fn = fn;
    // 系统bind在调用bind时可以传入部分参数,然后返回函数可以继续传入剩余参数
    var allParams = [...args, ...params];
    var result = thisArg.fn(...allParams);
    delete thisArg.fn;
    return result;
  };
};

函数的arguments

介绍

arguments是一个伪数组,伪数组具有数组的一些特效,但是却不是一个数组,而是一个对象。

  • arguments会将函数调用时传入的参数全部放入其中

  • arguments可以和数组一样具有 length属性

  • arguments可以和函数一样通过下标访问内部数据

  • arguments具有callee属性,指向的是本函数

function foo(num1, num2) {
  console.log(arguments.callee);
}
foo(10, 20, 30, 40);
// 打印
// ƒ foo(num1, num2) {
//     console.log(arguments.callee);
//   }

注意:箭头函数内是不绑定arguments的,箭头函数内使用arguments,那么会把arguments当作一个变量来处理,会沿着作用域链来查找。

arguments在浏览器的全局作用域上是不存在的,但在node上是存在的,因为在node里每一个js文件都是放到一个函数内执行的(node源代码操作),这个函数上就有arguments,node内打印arguments的话,就是这个函数的arguments。

arguments转array

function foo(num1, num2) {
  console.log(arguments); // Arguments(4) [10, 20, 30, 40, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  // 1、 手动遍历转换
  var newArray1 = [];
  for (var i = 0; i < arguments.length; i++) {
    // newArray1[i] = arguments[i];
    newArray1.push(arguments[i]);
  }
  console.log(newArray1); // [10, 20, 30, 40]
  // 2、数组方法转换 (也可以使用apply方法)
  var newArray2 = Array.prototype.slice.call(arguments);
  console.log(newArray2); // [10, 20, 30, 40]

  var newArray3 = [].slice.call(arguments);
  console.log(newArray3); // [10, 20, 30, 40]

  // es6语法
  var newArray4 = Array.from(arguments);
  console.log(newArray4); // [10, 20, 30, 40]

  var newArray5 = [...arguments];
  console.log(newArray5); // [10, 20, 30, 40]
}
foo(10, 20, 30, 40);

知识补充:Array内slice方法的实现

之所以在arguments转array时方法二可以这样调用是因为内部是这样实现的:

Array.prototype.msislice = function (start, end) {
  // 这里的this指向的是需要操作的数组
  var array = this;
  start = start || 0;
  end = end || array.length;
  var newArr = [];
  for (var i = start; i < end; i++) {
    newArr.push(array[i]);
  }
  console.log(newArr);
  return newArr;
};
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].msislice();
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].msislice(5);
// [6, 7, 8, 9, 0]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].msislice(1, 5);
// [2, 3, 4, 5]

以上是关于手写callapplybind函数和arguments&数组函数slice的实现的主要内容,如果未能解决你的问题,请参考以下文章

JS

手写JS面试题 --- call apply bind 实现

callapplybind 的区别?call 和 apply 哪个性能会更好?如何实现 callapplybind?

callapplybind的区别

js中的callapplybind

闭包,闭包用途,callapplybind 的用法