参考链接https://lq782655835.github.io/blogs/js/js-polyfill.html
1、实现发布订阅模式
// 发布订阅
const event = {
obj: {},
on: function(name, fn) {
(this.obj[name] || this.obj[name] = []).push(fn)
},
emit: function(name, ...args) {
if (Array.isArray(this.obj[name])) {
this.obj[name].forEach(fn => fn.call(this, ...args))
}
}
}
2、Promise.race
Promise.race = (promises) => {
return new Promise((onResolve, onReject) => {
for (p of promises) {
// 谁快谁先onResolve输出
Promise.resolve(p).then(onResolve, onReject)
}
})
}
3、promise.all(Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值(失败优先)。)
Promise.all = (promises) => {
return new Promise((onResolve, onReject) => {
let result = [], ;
// promise为空时,直接return
if (!promises.length) {
onResolve(result)
return
}
let pending = i = promises.length
let processPromise = (i) => {
promises[i].then(value => {
result[i] = value // 收集结果
// 当收集完时,onResolve返回
if (!--pending) {
onResolve(result)
}
}, onReject)
}
while(i--) {
processPromise(i)
}
})
}
//实现promise.all()
const promiseAll = function(promises){
let resolveNum = 0 //记录resolve的条数
let array = Array.from(promises)//数据的兼容性处理
let length = array.length
let lists = new Array(length)
return new Promise((resolve,reject)=>{
for(let i = 0 ; i < length-1 ; i ++ ){
Promise.resolve(array[i]).then((res)=>{
lists[i]=res
resolveNum++
if(resolveNum === length){
return resolve(lists)
}
}).catch((err)=>{
return reject(err)
})
}
})
}
4、深浅拷贝
// 浅拷贝
function clone(source) {
var target = {}
for (var i in source) {
source.hasOwnProperty(i) && target[i] = source[i]
}
return target
}
// or es6
const clone = source => Object.assign({}, source)
const clone = source => { ...source }
// 深拷贝
// 思路:递归赋值
const deepClone = obj => {
const isObj = obj => typeof obj === 'object' || typeof obj === 'function' && obj !== null
if (!isObj(obj)) {
throw new Error('不是对象')
}
// 区分array和object对象
let target = Array.isArray(obj) ? [] : {}
// https://stackoverflow.com/questions/34449045/what-is-the-difference-between-reflect-ownkeysobj-and-object-keysobj
Reflect.ownKeys(obj).forEach(key => {
target[key] = isObj(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return target
}
// 优化:以上未考虑到对象循环引用
const isObject = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function');
const isFunction = obj => typeof obj === 'function'
function deepClone (obj, hash = new WeakMap()) {
if (hash.get(obj)) {
// 环处理
return hash.get(obj);
}
if (!isObject(obj)) {
// 基本数据处理
return obj;
}
if (isFunction(obj)) {
// function返回原引用
return obj;
}
let cloneObj;
const Constructor = obj.constructor;
switch (Constructor) {
// 包装函数处理,可能是new Boolean(false)
case Boolean:
case Date:
return new Date(+obj);
case Number:
case String:
case RegExp:
return new Constructor(obj);
default:
cloneObj = new Constructor(); // 重要:初始化cloneObj类型
hash.set(obj, cloneObj);
}
[...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)].forEach(k => {
cloneObj[k] = deepClone(obj[k], hash);
})
return cloneObj;
}
// or 取巧方法
// 注意这种取巧方法是有限制的
// 1. 只能解析Number、String、Array等能够被json表示的数据结构
// 2. 不能处理循环引用
const deepClone = source => JSON.parse(JSON.stringify(source))
5、展平数组(可以指定深度)
// before: [1,2,3,[1, [2]], [1, [2, [3]]]]
// after: [ 1, 2, 3, 1, 2, 1, 2, [ 3 ] ]
function flatDeep(arr, depth = 1) {
if (depth === 1) return arr.reduce((pre, val) => pre.concat(val), [])
return arr.reduce((pre, val) => pre.concat(Array.isArray(val) ? flatDeep(val, depth - 1) : val), [])
}
6、展平数组,直接展到第
// before: [1,2,3,[1,2,3,4, [2,3,4]]]
// after flatDeep: [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
// 思路:深度优先递归,使用reduce连接起来
// 深度优先算法 - 递归
function flatDeep(arr) {
return arr.reduce((pre, val) => pre.concat(Array.isArray(val) ? flatDeep(val) : val), [])
}
// 深度优先算法 - 堆栈
function flatDeep(arr) {
const stack = [...arr]
const res = []
while (stack.length) {
const val = stack.pop() // 从尾部开始
Array.isArray(val) ? stack.push(...val) : res.push(val)
}
return res.reverse()
}
// 取巧,利用Array.toString()
function flatDeep(arr) {
return arr.toString().split(',')
}
7、new
_new() {
var object = new Object() // 1. 类都是object类型
var Constructor = [].shift.call(arguments)
var args = arguments // 剩下的参数
object.__proto__ = Constructor.prototype // 2. 设置原型链
var ret = Constructor.apply(obj, args) // 3. 构造函数执行
return typeof ret === 'object' ? ret : obj
}
_new(Foo, 'name')
// es6
_new(Constructor, ...args) {
let object = Object.create(Constructor.prototype)
let ret = Constructor.apply(object, args)
return typeof ret === 'object' ? ret : obj
}
8、call、apply
Function.prototype.call = function(context, ...args) {
context = context || window
context.fn = this // 这里的this代表函数
context.fn(...args) // 给context添加属性fn,所以执行fn方法时,里面的this代表context
delete context.fn
}
Function.prototype.apply = function(context, ...args) {
context = context || window
context.fn = this
context.fn(args) // apply传递数组
delete context.fn
}
9、防抖
// 防抖--------某一时间段内只执行一次
// 搜索或者用户调用触发resize的时候
function debounce(fn,time){
let timer = null
return function(){
let that = this
if(timer){
clearTimeout(timer)
}
timer = setTimeout(()=>{
fn.apply(that,arguments)
},time)
}
}
// 节流----------间隔时间执行
//鼠标不断的点击,监听滚动事件
function throttle(fn,time){
var previous = 0
return function(){
let that = this
let _argus = arguments
let now = Date.now()
if(now-previous>time){
fn.apply(that,_argus)
previous = now
}
}
}
// Array.prototype.map = function(func,callBackThis){
// return this.reduce((accu,currentValue,currentIndex,array)=>{
// accu.push(func.call(callBackThis,currentValue,currentIndex,array))
// return accu
// },[])
// }
// 实现instanceof
myInstance = function(left,right){
let proto = left._proto_
let prototype = right.prototype
while(true){
if(proto===prototype){
return true
}
if (proto === null) return false
proto = proto._proto_
}
}
// 实现curry
myCurry = function(){
}
//实现 flatMap
myFlatMap=function(arr,deep){
var result = []
for(let i = 0 ; i < arr.length ; i++){
if(Array.isArray(arr[i])){
result.concat(myFlatMap(arr[i]))
}
else{
result.push(arr[i])
}
}
return result
}
10、实现reduce
Array.prototype._reduce = function(callback, initvalue) {
let i = 0;
let result = initvalue
if (typeof initvalue === 'undefined') {
result = this[0]
i++
}
for (let i = 0; i < this.length; i++) {
result = callback(result, this[i])
}
return result
}
11、reduce 实现map
// reduce 实现map
Array.prototype.map = (func,callBackThis)=>{
return this.reduce((accu,currentValue,currentIndex,array)=>{
accu.push(func.call(callBackThis,currentValue,currentIndex,array))
return accu
},[])
}