Js实现call、apply、bind ,arguments解析

57 阅读3分钟

一、Js实现call、apply、bind

1、call

// apply/call/bind的用法
// js模拟它们的实现? 难度
// 给所有的函数添加一个hycall的方法
Function.prototype.hycall = function(thisArg, ...args) {
  // 在这里可以去执行调用的那个函数(foo)
  // 问题:得可以获取到是哪一个函数执行了hycall
  // 1.获取需要被执行的函数
  var fn = this

  // 2.对thisArg转成对象类型(防止它传入的是非对象类型) 
  thisArg = (thisArg != null || thisArg != undefined) ? Object(thisArg) : window   // 排除null undefined

  // 3.调用需要被执行的函数
  // fn.call(thisArg)
  thisArg.fn = fn
  var result =  thisArg.fn(...args);
  delete thisArg.fn

  // 4.将最终的结果返回出去
  return result;
  // console.log(thisArg,"hycall被调用");
}


function foo() {
  console.log("foo函数被执行",this);
}

function sum(sum1, sum2) {
  console.log("sum函数被执行",this, sum1, sum2);
  return sum1 + sum2

}

// 系统的函数call方法
// foo.call();

// 自己实现的hycall的方法
sum.hycall('1111', 20,30);
var endNum = sum.hycall('1111', 20,30);
console.log(endNum,"最终的结果");
// foo.hycall('1111', 20,30);
Function.prototype.hycall = 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

}

2、apply

// 自己实现hyapply
Function.prototype.hyapply = function(thisArg, argArray) {
    // 在这里可以去执行调用的那个函数(foo)
    // 问题:得可以获取到是哪一个函数执行了hyapply

    // 1.获取需要被执行的函数
    var fn = this

    // 2.对thisArg转成对象类型(防止它传入的是非对象类型)  0 
    thisArg = (thisArg != null || thisArg != undefined) ? Object(thisArg) : window   // 排除null undefined

    argArray = argArray || []

    // 3.调用需要被执行的函数
    // fn.call(thisArg)
    thisArg.fn = fn
    var result =  thisArg.fn(...argArray);
    delete thisArg.fn

    // 4.将最终的结果返回出去
    return result;
}


function sum(num1, num2) {
    console.log("sum被调用", this, num1, num2);
    return num1 + num2
}


// 系统调用
// sum.apply("abc",[20,30])


// 自己实现
var result = sum.hyapply("abc",[20, 30])
console.log(result,"最后的结果");

sum.hyapply('abc')
Function.prototype.hyapply = function(thisArg, args) {
  var fn = this;
  thisArg = (thisArg != null || thisArg != undefined) ? Object(thisArg) : window;
  thisArg.fn = fn;
  args = args || []
  var result = thisArg.fn(...args)
  delete thisArg.fn
  return result

}

3、bind

// apply/call/bind的用法
// js模拟它们的实现? 难度
// 给所有的函数添加一个hybind的方法
Function.prototype.hybind = function(thisArg, ...argArray) {
  // 在这里可以去执行调用的那个函数(foo)
  // 问题:得可以获取到是哪一个函数执行了hybind
  // 1.获取需要被执行的函数
  var fn = this

  // 2.对thisArg转成对象类型(防止它传入的是非对象类型) 
  thisArg = (thisArg != null && thisArg != undefined) ? Object(thisArg) : window   // 排除null undefined

  function proxyFn(...args) {
    // 3.调用需要被执行的函数
    thisArg.fn = fn
    var finalArgs = [...argArray, ...args]
    var result =  thisArg.fn(...finalArgs);
    delete thisArg.fn


    // 4.将最终的结果返回出去
    return result;
  }

  return proxyFn;
}


function sum(sum1, sum2, sum3, num4) {
  console.log("sum函数被执行",this, sum1, sum2, sum3, num4);
  return sum1 + sum2 + sum3

}

// 系统的函数bind方法
// sum.bind('1111')(20,30,50);

// 自己实现的hybind的方法
// sum.hybind('1111', 20,30);
var endNum = sum.hybind('1111', 20,30, 50);
var endSum = endNum(60, 70)
console.log(endSum,"最终的结果");
Function.prototype.hybind = function(thisArg, ...argArray) {
  var fn = this;
  thisArg = (thisArg != null || thisArg != undefined) ? Object(thisArg) : window

  function proxyFn(...args) {
    thisArg.fn = fn
    var finalArgs = [...argArray, ...args]
    var result = thisArg.fn(...finalArgs)
    delete thisArg.fn
    return result

  }
  return proxyFn
}

二、arguments解析

1.arguments基本使用

f0981cccb90f6c3265a68cbda1547cc.png

function foo(num1, num2, num3) {
  // 类数组对象中(长得像是一个数组,本质上是一个对象) arguments
  console.log(arguments);

  // 常见的对arguments的操作十三个
  // 1.获取参数的长度
  console.log(arguments.length);

  // 2.根据索引值获取某一个参数
  console.log(arguments[1]);

  // 3. callee获取当前arguments所在的函数
  console.log(arguments.callee);

  console.log(num1, num2, num3 );
}


foo(10, 20, 30, 40, 50)

2.argument转成array类型数据

Array中的slice实现:

function foo(num1, num2) {
    console.log(arguments);
    // 1.自己遍历
    // var newArr = []
    // for (var i = 0; i < arguments.length; i++) {
    //     newArr.push(arguments[i]*10);
        
    // }
    // console.log(newArr);

    // 2.arguments转成数组类型
    // var newArr2 = Array.prototype.slice.call(arguments)
    // console.log(newArr2);

    // var newArr3 = [].slice.call(arguments)
    // console.log(newArr3);

    // ES6语法
    // var newArr4 = Array.from(arguments)
    // console.log(newArr4);

    var newArr5 = [...arguments]
    console.log(newArr5);
}

foo(10, 20, 30, 40)



// 额外补充的知识点: Array中的slice实现
// Array.prototype.hyslice = function(start, end) {
//   var arr = this
//   start = start || 0
//   end = end || arr.length
//   var newArray = []
//   for (var i = start; i < end; i++) {
//     newArray.push(arr[i])
//   }
//   return newArray
// }

// var newArray = Array.prototype.hyslice.call(["aaaa", "bbb", "cccc"], 1, 3)
// console.log(newArray)

// var names = ["aaa", "bbb", "ccc", "ddd"]
// console.log(names.slice(1, 3));
Array.prototype.hyslice = function(start, end) {
  var arr = this
  start = start || 0
  end = end || arr.length
  var newArray = []
  for (var i = start; i < end; i++) {
    newArray.push(arr[i])
  }
  return newArray
}

1、 var newArr2 = Array.prototype.slice.call(arguments)
2、 var newArr3 = [].slice.call(arguments)
3、 var newArr4 = Array.from(arguments)
4、 var newArr5 = […arguments]

3.箭头函数中没有arguments

// 1.案例一:
// var foo = () => {
//     console.log(arguments);
// }


// function bar() {
//     console.log(arguments);
// }

// foo()

// 2.案例二:
// function foo() {
//   var bar = () => {
//     console.log(arguments)
//   }
//   return bar
// }

// var fn = foo(123)
// fn()

// 3.案例三:
var foo = (num1, num2, ...args) => {
    console.log(args)
  }
  
  foo(10, 20, 30, 40, 50)