跟着coderwhy学习JavaScript高级(五)

228 阅读2分钟

call/apply/bind底层是c++实现的,js能达到一个模拟器的效果,这里不过多的考虑边界问题

实现call

/**
 * 简易版的call 
 * @param {*} thisArg 需要绑定的this 这里做一个简单的边界处理
 * @param  {...any} args 参数
 */
Function.prototype.mycall = function (thisArg,...args) {

  // 如果用户传的undefined 或 null 那么this指向window
  // Object是为了包装一下  可能用户传数字啥的...(简单的边界处理)
  thisArg = (thisArg == null) ? window : Object(thisArg)

  // 当前的this是什么?谁调用我,我就是谁 既然是foo.mycall() this是foo
  thisArg.fn = this

  // 改变this的关键 thisArg是用户传进来的 老规矩 隐式绑定this
  // 假设用户传进来的是{} 那么就是 {}.fn() 那this就会被隐式绑定成 {}
  var res = thisArg.fn(...args)
  // 删除多余的属性
  delete thisArg.fn

  return res
}

function foo(num1, num2) {
  console.log(this)
  return num1 + num2
}

var x = foo.mycall({},1,2)
console.log(x)

实现apply

/**
 * 
 * @param {*} thisArg 需要绑定的this 这里做一个简单的边界处理
 * @param {*} argArray 参数 是一个数组
 * @returns 
 */
 Function.prototype.myapply = function (thisArg, argArray) {

      // 不用判断用户传进来的是否为数组,因为...拓展运算符 不是数组会报错

      // thisArg 如果传 undefined 或者 null 会指向 window
      // thisArg == null 包含了 undefined 和 null
      // 用Object是为了包装一下  可能用户传数字啥的...(简单的边界处理)
      var thisArg = (this == null) ? window : Object(thisArg)

      var fn = this
      thisArg.fn = fn

      var result;
      // 写法1:
      // if (!argArray){ // argArray是没有值(没有传参数)
      //   result = thisArg.fn()
      // } else{ //argArray有参数
      //   result = thisArg.fn(...argArray)
      // }

      // 写法2:
      // argArray = argArray ? argArray : []
      // result = thisArg.fn(...argArray)

      // 写法3:
      argArray = argArray || []
      result = thisArg.fn(...argArray)
      delete thisArg.fn

      return result
    }


    function foo(num1, num2) {
      console.log(this)
      return num1 + num2
    }

    let res = foo.apply({}, [1,2])
    console.log(res)

实现bind

Function.prototype.mybind = function (thisArg, ...argArray) {
  thisArg = (thisArg == null) ? window : Object(thisArg)

  thisArg.fn = this

  return function (...newArgs) {
    var args = [...argArray,...newArgs]
    return thisArg.fn(...args)
  }

}


function foo(num1, num2) {
  console.log(this)
  return num1 + num2
}

var x = foo.mybind({},1,2)
console.log(x())

arguments的基本使用

function bar(num1, num2, num3) {

  // 1.获取参数长度
  console.log(arguments.length)

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

  // 3.callee获取当前arguments所在函数 可以直接调用
  console.log(arguments.callee)
  // arguments.callee()
}
bar(1,23,4,5,6,7,7)

伪数组转数组的方式

function foo(num1, num2, num3) {
  // 手工遍历
  var newArray = [];
  for (var i = 0; i < arguments.length; i++) {
    newArray.push(arguments[i]);
  }
   
  var newArray1 = Array.prototype.slice.call(arguments)

  var newArray2 = [].slice.call(arguments)

  var newArray3 = Array.from(arguments)

  var newArray4 = [...arguments]

  console.log(newArray, newArray1, newArray2, newArray3, newArray4)
}

foo(1,2,3,4,5)

实现slice

Array.prototype.myslice = function (start, end) {

  var start = start || 0
  var end = end || end.length
  var newArray = []

  for (var i = start; i < end; i++) {
      // 谁调用我 this就是谁
    newArray.push(this[i])
  }

  return newArray
}


var arr = [1,2,3,4];
console.log(arr.myslice(0,3))