实现JavScript相关方法

163 阅读1分钟

call / apply / bind

实现call

Function.prototype.myCall = function(ctx) {
    ctx = ctx ? Object(ctx) : window

    ctx.originFn = this

    var args = []

    for (let i = 1; i < arguments.length; i++) {
        args.push('arguments[' + i + ']')
    }

    var res = eval('ctx.originFn(' + args + ')')

    delete ctx.originFn

    return res
}

实现apply

Function.prototype.myApply = function(ctx, args) {
    ctx = ctx ? Object(ctx) : window
    ctx.originFn = this
    
    if(typeof args !== 'object' && typeof args !== 'function') {
        throw new Error('CreateListFromArrayLike called on non-object')
    }

    if (!args || {}.toString.call(args) !== '[object Array]') {
        return ctx.originFn()
    }

    var res = eval('ctx.originFn(' + args + ')')
    delete ctx.originFn
    return res
}

实现bind

Function.prototype.myBind = function(ctx) {
    var originFn = this
    var args = [].slice.call(arguments)
    var temp = function() {}

    var newFn = function () {
        var newArgs = [].slice.call(arguments)
        // this指向考虑new构造情况
        originFn.apply(this instanceof newFn ? newFn : ctx, args.concat(newArgs))
    }

    temp.prototype = this.prototype
    newFn.prototype = new temp()

    return newFn
}

实现new操作

function _new() {
    var construct = [].shift.call(arguments)
    var _this = {}

    _this.__proto__ = construct.prototype

    var res = construct.apply(_this, arguments)
    return {}.toString.call(res) === '[object Object]' ? res : _this
}

实现instanceof

function myInstanceof(target, type) {
    target = target.__proto__
    type = type.prototype

    while(true) {
        if (target === null) return false

        if (target === type) return true

        target = target.__proto__
    }
}

实现深浅拷贝

function deepClone(origin, target) {
    var tar = target || {}
    var toString = Object.prototype.toString
    var typeArr = '[object Array]'

    for (let k in origin) {
        if (origin.hasOwnProperty(k)) {
            if (typeof origin[k] === 'object' && origin[k] !== null) {
                tar[k] = toString.call(origin[k]) === typeArr ? [] : {}
                deepClone(origin[k], tar[k])
            } else {
                tar[k] = origin[k]
            }
        }
    }

    return tar
}

实现数组相关方法

实现forEach

Array.prototype.myForEach = function(cb) {
    var arg2 = arguments[1] || window
    var arr = this
    var len = arr.length

    for (var i = 0; i < len; i++) {
        cb.apply(arg2, [arr[i], i, arr])
    }
}

实现map

Array.prototype.myMap = function(cb) {
    var arr = this
    var len = arr.length
    var arg2 = arguments[1] || window
    var res = []
    var item

    for (var i = 0; i < len; i++) {
        item = deepClone(arr[i])
        cb.apply(arg2, [item, i, arr]) && res.push(cb.apply(arg2, [item, i, arr]))
    }

    return res
}

实现filter

Array.prototype.myFilter = function(cb) {
    var arr = this
    var len = arr.length
    var arg2 = arguments[1] || window
    var res = []
    var item

    for (var i = 0; i < len; i++) {
        item = deepClone(arr[i])
        cb.apply(arg2, [item, i, arr]) ? res.push(item) : ''
    }

    return res
}

实现every

Array.prototype.myEvery = function(cb) {
    var arr = this
    var len = arr.length
    var arg2 = arguments[1] || window
    var res = true

    for (var i = 0; i < len; i++) {
        if (!cb.apply(arg2, [arr[i], i, arr])) {
            res = false
            break
        }
    }
    
    return res
}

实现some

Array.prototype.mySome = function(cb) {
    var arr = this
    var len = arr.length
    var arg2 = arguments[1] || window
    var res = false

    for (var i = 0; i < len; i++) {
        if (cb.apply(arg2, [arr[i], i, arr])) {
            res = true
            break
        }
    }

    return res
}

实现reduce

Array.prototype.myReduce = function(cb, initialVal) {
    var arr = this
    var len = arr.length
    var arg3 = arguments[2] || window
    var item

    for (var i = 0; i < len; i++) {
        item = deepClone(arr[i])
        initialVal = cb.apply(arg3, [initialVal, item, i, arr])
    }

    return initialVal
}

实现reduceRight

Array.prototype.myReduceRight = function(cb, initialVal) {
    var arr = this
    var len = arr.length
    var arg3 = arguments[2] || window
    var item

    for (var i = len; i >= 0; i--) {
        item = deepClone(arr[i])
        initialVal = cb.apply(arg3, [initialVal, item, i, arr])
    }

    return initialVal
}

实现对象相关方法

实现Object.assign()

Object.myAssign = function (target, ...sources) {
  sources.forEach((source) => {
    const descriptors = Object.keys(source).reduce((descriptor, key) => {
      descriptor[key] = Object.getOwnPropertyDescriptors(source, key)
      return descriptors
    }, {})
    Object.defineProperties(target, descriptors)
  })
  return target
}

实现Object.entries()

Object.myEntries = function (o) {
  var res = []
  var objTpye = '[object Object]'

  if ({}.toString.call(o) === objTpye) {
    for (var k in o) {
      if (o.hasOwnProperty(o)) {
        res.push([k, o[k]])
      }
    }
  }
  
  return res
}

实现Object.fromEntries()

Object.myFromEntries = function (o) {
  var obj = {}

  for (var item of o) {
    obj[item[0]] = item[1]
  }

  return obj
}

实现Object.freeze()

Object.deepFreeze = function (o) {
  var key = Object.getOwnPropertyNames(o)

  if (key.length) {
    key.forEach(function(k) {
      var value = o[k]

      if (typeof value === 'object' && value !== null) {
        Object.deepFreeze(value)
      }
    })
  }

  return Object.myFreeze(o)
}

实现Object.seal()

Object.deepSeal = function (o) {
  var key = Object.getOwnPropertyNames(o)

  if (key.length) {
    key.forEach(function(k) {
      var value = o[k]
      if (typeof value === 'object' && value !== null) {
        Object.deepSeal(value)
      }
    })
  }

  return Object.seal(o)
}

实现Object.preventExtensions()

Object.deepPreventExtensions = function (o) {
  var key = Object.getOwnPropertyNames(o)

  if (key.length) {
    key.forEach(function(k) {
      var value = o[k]
      if (typeof value === 'object' && value !== null) {
        Object.deepPreventExtensions(value)
      }
    })
  }

  return Object.preventExtensions(o)
}