js基础 手写const 回到var和let/const的区别上:
var声明的变量会挂到window上,而let和const不会
实现const的关键在于Object.defineProperty()这个API,这个API用于在一个对象上增加或修改属性。通过配置属性描述符,可以精确地控制属性行为。Object.defineProperty() 接收三个参数:Object.defineProperty(obj, key, desc)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var  __const = function  __const  (data, value )   window .data = value    Object .defineProperty(window , data, {      enumerable: false ,     configurable: false ,     get : function () {       return  value     },     set : function (data) {       if  (data !== value) {          throw  new  TypeError ('Assignment to constant variable.' )       } else  {         return  value       }     }   }) } __const('a' , 10 ) console .log(a)delete  aconsole .log(a)
mock Promise(精简,重点是明白其中异步调用原理) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class  MyPromise  	constructor (executor) { 		this .cbs = []; 		this .data = undefined ; 		var  resolve = (data ) =>  { 			setTimeout(()  => 				this .data = data 				this .cbs.forEach(cb  => 			}) 		} 		executor(resolve) 	} 	then(onResolved, onReject) { 		return  new  MyPromise(resolve  => 			this .cbs.push(()  =>         const  data = onResolved(this .data)         if  (data instanceof  MyPromise) {             data.then(resolve)         } else  {             resolve(data)         } 			}) 		}) 	} } 
测试案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 new  MyPromise((resolve ) =>  {    console .log('start' )     setTimeout(()  =>     	resolve(1 );     }, 500 ); }) .then((res ) =>  {     console .log(res);     return  new  MyPromise((resolve ) =>  {         setTimeout(()  =>             resolve(2 );         }, 500 );     }); }) .then(console .log); console .log('end line' )
mock Promise.all Promise.all() 方法会将多个 Promise 实例组合成一个新的 Promise 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 Promise .myAll = function (arr )   return  new  Promise ((resolve, reject ) =>  {     let  res = []     for (let  [i, item] of  arr.entries()) {       Promise .resolve(item).then(         data => {           res.push(data)           if  (i === arr.length -1 ) {             resolve(res)           }             },         error => {           reject(error)         }       )     }   }) } var  p1 = Promise .resolve( 1  );var  p2 = Promise .resolve( Promise .resolve( '111'  ) );var  p3 = Promise .resolve('error' )Promise .all([p1, p2, p3]).then(  res => {     console .log(res)   },   err => {     console .warn(err)   } ) Promise .myAll([p1, p2, p3]).then(  res => {     console .log(res,'my' )   },   err => {     console .warn(err, 'muy' )   } ) 
Mock Promise.any Promise.all的反向操作,只有当每个包含的Promise实例都拒绝了,合成的promise才会拒绝rejected
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Promise .myAny = function (arr )   return  new  Promise ((resolve, reject ) =>  {     let  res = []     for  (let  [index, item] of  arr.entries()) {       return  Promise .resolve(item).then(         (data) => {           resolve(data)         },         (err) => {           if  (index === arr.length -1 ) {             reject(err)           }           res.push(err)         }       )     }   }) } 
mock Promise.race 只要有一个请求有响应值,请求就会结束,返回有响应的那个promise结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Promise .myAny = function (arr )   return  new  Promise ((resolve, reject ) =>  {     for  (let  [index, item] of  arr.entries()) {       return  Promise .resolve(item).then(         success: (data ) =>  {           resolve(data)         },         error: (err ) =>  {           reject(err)         }       )     }   }) } 
mock Promise.allSettled(es7+) Promise.allSettled() 方法也是返回一个合成的 Promise,不过只有等到所有 Promise 实例都返回结果落定时,不管是解决(fulfilled)还是拒绝(rejected),合成的 Promise 才会结束。一旦结束,状态总是 fulfilled。
等所有的成功和失败的结果都有了才会返回promise结果,成功的时候返回[{value: '', status: 'fifulled'}],失败的时候返回[{reason: '', status: 'rejected'}],组成一个失败和成功的组合的promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 Promise .prototype.myAllSettled = function (arr )   return  new  Promise ((resove, reject ) =>  {     let  res     for  (let  [index, item] of  arr.entries()) {       Promise .resolve(item).then(         data => {           res[i] = {             value: data,             status: 'fifulled'            }           if  (index + 1  === arr.length) {             resove(res)           }         },         error => {           res[i] = {             value: error,             status: 'rejected'            }           if  (index + 1  === arr.length) {             resove(res)           }         }       )     }   }) } Promise .prototype.myAllSettled = function (arr )   var  PromiseAll = [...arr]   return  Promise .all(PromiseAll.map(e) => {     return  Promise .resolve(e).then(       data => {status : 'fulfilled' , value : data},       err  => {status : 'rejected' , reason : err}     )   }) } 
实现一个并发控制器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 async  function  asyncPool (limit, arr, fn )   try  {     const  res = []      let  executing = []      for  (let  i = 0 ; i < arr.length; i ++) {       var  p1 = Promise .resolve().then(()  =>this , i))       res.push(p1)       if  (limit <= arr.length) {         const  cur = Promise .resolve(p1).then(()  =>           return  executing.splice(executing.indeOf(cur),1 )         })         executing.push(cur)         if  (executing.length >= limit) {           await  Promise .race(executing)         }       }     }     return  Promise .all(res)   } catch (err) {     console .log(err)   } } const  timeFn = i  =>  return  new  Promise ((resolve ) =>      setTimeout(()  =>   ) } var  arr = [1000 , 1000 , 1000 , 1000 , 1000 , 1000 , 1000 , 1000 , 1000 , 1000 ]asyncPool(2 , arr2, null ).then((res ) =>  {   console .log(`res` , res) }) 
mock async 1 2 3 4 5 6 7 8 9 10 const  getData = ()  =>new  Promise (resolve  =>()  =>"data" ), 1000 ))async  function  test (  const  data = await  getData()   console .log('data: ' , data);   const  data2 = await  getData()   console .log('data2: ' , data2);   return  'success'  } test().then(res  =>console .log(res)) 
手写async(22行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 function  asyncGenerator (fn )   return  function (   const  gen = fn.apply(this , arguments )     return  new  Promise ((resolve, reject ) =>  {       function  step (key, arg )          let  generatorResult         try  {           generatorResult = gen[key](arg)         } catch (e) {           reject(e)         }         const  {value, done} = generatorResult;         if  (done) {           return  resolve(value)         } else  {           return  Promise .resolve(value).then(             val => step('next' , val),             err => step('throw' , err)           )         }       }       step('next' )     })   } } var  getData = ()  =>new  Promise ((resolve ) =>  setTimeout(()  =>'data' ), 1000 ))var  test = asyncGenerator(	function * testG (     const  data = yield  getData()     console .log('data1: ' , data);     const  data2 = yield  getData()     console .log('data2: ' , data2);     return  'success'  	} ) test().then(res  =>console .log(res, 'cpp' )) 
封装一个类使对象可以被for of遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class  MakeIterator  	constructor (obj) { 		this .obj = obj; 		this .len = Object .keys(obj).length; 		this .index = 0 ; 	} 	[Symbol .iterator]() {return  this ;} 	next() { 		if  (this .index < this .len) { 			return  { 				value: this .obj[this .index ++], 				done: false  			} 		} else  { 			return  { 				value: undefined , 				done: true  			} 		} 	} } var  obj = {  0 : 'wmh' ,   1 : 'cpp' ,   2 : 'chendap' , 	length: 3  } for  (var  item of  new  MakeIterator(obj)) {    console .log(item) } 
Bind 一句话介绍: bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
返回一个新函数
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Function .protptyoe.mockBind = function (context, ...rest )   var  self = this ;   var  fNOP = function (   var  fbound =  function (...arg )      var  args = [...rest, ...arg];               self.apply(this  instanceof  self ? this  : context, args)   }   fNOP.prototype = this .prototype;   fbound.prototype = new  fNOP()   return  fbound } function  sayName (name, age )   console .log(this .value);    console .log(name);   console .log(age); } Function .prototype.mockBind = mockBind;var  sayFnMock = sayName.mockBind(obj2, 'wmh' )var  resMock = new  sayFnMock('菜鸟Mock' )console .log(resMock, 'Mock的bind返回的值' )
感谢冴羽大佬提供的高水平文章-JavaScript深入之bind的模拟实现 
 
Apply 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Function .prototype.mockApply = function (context, args ) 	var  context = context || window ; 	var  sym = Symbol ();  	context[sym] = this ; 	      let  result = eval ('context.sym(...args)' ) 	delete  context[sym] 	return  result } const  obj = {  name: 'cpp'  } function  sayName (name )   alert(name) } Function .prototype.mockApply = mockApplysayName.mockApply(obj, ['菜鸟' ]) Function .prototype.mockCall = function  (context, ...args )   var  context = context || window ;   context.fn = this ;   var  result = eval ('context.fn(...args)' );   delete  context.fn   return  result; } 
new step one: 创建一个空对象 obj;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function  mockNew (con, ...rest ) 	let  obj = Object .create(con.prototype) || window ;  	let  res = con.apply(obj, rest)  	return  res instanceof  Object  ? res : obj;  } function  SayName (name ) 	this .name = name } SayName.prototype.emit = function ( 	console .log(name) } var  test = new  SayName('cpp' )console .log(test)var  test1 = mockNew(SayName, 'cpp' )console .log(test1)
instanceof 判断一个实例是否是其父类或者祖先类型的实例。
1 2 3 4 5 6 7 8 9 function  mockInstanceof (target, origin ) 	while (target) { 		if (target.__proto__ === origin.prototype) {return  true } 		target = target.__proto__ 	} 	return  false  } console .log([1 ,2 ] instanceof  Array ) mockInstanceof([1 ,2 ], Array )  
curry 函数柯里化 第一种 参数固定(有局限,形参个数固定) 1 2 3 4 5 6 7 8 9 10 11 12 13 function  curry (fn )   let  judge = (...args ) =>  {     if  (args.length === fn.length) {       return  fn(...args)     }     return  (...arg ) =>  judge(...args, ...arg)   }   return  judge } var  add = (a, b, c ) =>  a + b + c;var  addCurry = curry(add)addCurry(1 )(2 )(3 )  
第二种,参数不固定(自由灵活) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function  add (...arr )   return  arr.reduce((a, b ) =>  a + b) } function  curry (fn )   var  arr = []   return  function  temp (...rest )      if (rest.length) {       arr.push(...rest);       return  temp;     } else  {       const  val = fn.apply(this , arr)       arr = []       return  val     }   } } var  addFn = curry(add)var  test = addFn(3 )(1 )(5 )(44 )() 
实现一个方法进行求和 1 2 3 4 5 var  foo = function (...args )    } var  f1 = foo(1 )(2 )(3 )f1.getValue() 
答案 1 2 3 4 5 var  foo = function (...args )   var  target = (...arg ) =>  foo(...[...args, ...arg])   target.getValue = ()  =>(a, b ) =>  a + b, 0 )   return  target } 
函数重载 因为ECMAScript函数的参数是由零或多个值的类数组表示的,没有函数签名(接收的参数的类型和数量),真正的重载是不能做到的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function  addMethod (obj, name, fn )   var  old = obj[name]   obj[name] = function (     let  arg = Array .from(arguments );      if (fn.length === arg.length) {       fn.apply(this , arg)     } else  if  (typeof  fn === 'function' ) {       old.apply(this , arg)     }   } } var  person = {userName : 'bear鲍的小小熊' }addMethod(person, 'show' , function  (   console .log(this .userName + '---->'  + 'show1' ) }) addMethod(person, 'show' , function  (str )    console .log(this .userName + '---->'  + str) }) addMethod(person, 'show' , function  (a, b )    console .log(this .userName + '---->'  + (a + b)) }) person.show()   person.show('bkl' ) person.show(10 , 20 ) 
防抖debounce 核心:采用异步线程setTimeout进行延迟执行,多次触发之后执行一次,典型场景就是防止多次提交的按钮
1 2 3 4 5 6 7 8 9 10 11 function  debounce (fn, wait ) 	let  timer 	return  function (...arg )  		if (timer) { 			clearTimeout(timer) 		} 		timer = setTimeout(()  => 			fn.apply(this , arg) 		}, wait) 	} } 
节流throttle 核心:每间隔多少秒执行一次,使之频率变低,典型场景:滚动事件
1 2 3 4 5 6 7 8 9 10 11 12 function  throttle (fn, wait ) 	let  pre = 0  	return  function (...args )  		let  now = new  Date ().getTime() 		let  that = this  		if (now - pre > wait) { 			fn.apply(that, args) 			pre = now 		} 	} } 
webpack Mock webpack,模拟webpack打包构建过程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 const  fs = require ('fs' );const  path = require ('path' )const  parser = require ('@babel/parser' )const  traverse = require ('@babel/traverse' )const  babel = require ('@babel/core' )const  getModuleInfo = (file ) =>  {  const  body = fs.readFileSync(file, 'utf-8' )   const  ast = parser.parse(body, {     sourceType: 'module'     })      const  deps = {}   traverse.default(ast, {     ImportDeclaration({node}) {       const  dirname = path.dirname(file)       const  depsPath = node.source.value       const  abspath = './'  + path.join(dirname, depsPath)       deps[depsPath] = abspath;     }   })   const  {code} = babel.transformFromAst(ast, null , {     presets: ['@babel/preset-env' ]   })   return  {     file,     deps,     code,   } } const  parseModules = (file ) =>  {  const  entry = getModuleInfo(file);   const  temp = [entry]   for  (let  i = 0 ; i < temp.length; i ++) {     const  deps = temp[i].deps;     if  (deps) {       for  (const  key in  deps) {         if  (deps.hasOwnProperty(key)) {           temp.push(getModuleInfo(deps[key]))         }       }      }   }      const  depsGraph = {}   temp.forEach((moduleInfo ) =>  {     depsGraph[moduleInfo.file] = {       deps: moduleInfo.deps,       code: moduleInfo.code,     }   })   return  depsGraph } const  bundle = (file ) =>  {  const  depsGraph = JSON .stringify(parseModules(file));   return  `(function (graph) {      function require(file) {       var exports = {};       function absRequire(relPath) {         console.log(relPath, 'relPath')         return require(graph[file].deps[relPath])       }       (function(require, exports, code){         console.log(code)         eval(code)       })(absRequire, exports, graph[file].code)       return exports     }     require('${file} ')   })(${depsGraph} )` } function  emit (path )   const  content = bundle(path)   const  distPath = './dist' ;   const  bundlePath = './dist/bundle.js'    fs.unlinkSync(bundlePath);   fs.rmdirSync(distPath);   fs.mkdirSync(distPath)   fs.writeFileSync(bundlePath, content) }; emit('./src/index.js' ) 
plugin 手写一个给打包文件头部注入作者和描述信息的webpack plugin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class  MyInfoPlugin    constructor (options = {     author: 'cpp' ,     description: 'plugin name'    }) {     this .options = options   }   get  pluginName() {     return  MyInfoPlugin.name   }   apply(compiler) {     compiler.hooks.emit.tapPromise(       this .pluginName,       async  (compilation) => {         const  options = this .options;         await  new  Promise ((resolve, reject ) =>  {           const  assets = compilation.assets;           Object .keys(assets).forEach((asset ) =>  {             let  source = assets[asset].source();             let  info = []             if  (options.author) {               info.push(`@Author: ${options.author} ` )             }             if  (options.description) {               info.push(`@Description: ${options.description} ` )             }             if  (info.length) {               info.push(`@Date: ${new  Date ()} ` )               source = `/*\n  ${info.join('\n  ' )} \n*/\n ${source} `              }             compilation.assets[asset].source = ()  =>             compilation.assets[asset].size = ()  =>           })           resolve('Success' )           reject('MyInfoPlugin 插件出问题咯' )         })       }     )   } } module .exports = MyInfoPlugin
测试
1 2 3 4 5 6 7 8 9 10 const  MyInfoPlugin = require ('../plugin/MyInfoPlugin' )module .exports = {  plugins: [     new  MyInfoPlugin({       author: 'chendapeng' ,       description: 'Test test description'      }),   ] } 
loader 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const  loaderUtils = require ('loader-utils' );const  validateOptions = require ('schema-utils' );const  schema = {  type: 'object' ,   properties: {     name: {       type: 'string'      }   } } module .exports = function  (source )      const  options = loaderUtils.getOptions(this )   validateOptions(schema, options, 'Example Loader' )   return  source } 
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 module .exports = {    resolveLoader: {       alias: {         'async-loader' : path.resolve(__dirname, '../loader/async-loader.js' )       }     },     module : {       rules: [         {           test: /\.js$/ ,           exclude: '/node_modules/' ,           use: [             {               loader: 'async-loader' ,               options: {                 name: 'test my loader cpp'                }             }           ]         }       ]     } } 
splitChunks Webpack中一个提取或分离代码的插件,主要作用是提取公共代码,防止代码被重复打包,拆分过大的js文件,合并零散的js文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 module .exports = {    configureWebpack:config  =>         return  {             optimization: {                 splitChunks: {                     chunks: 'async' ,                       minSize: 30000 ,                      maxSize: 0 ,                      minChunks: 1 ,                      maxAsyncRequests: 6 ,                      maxInitialRequests: 4 ,                      automaticNameDelimiter: '~' ,                                           cacheGroups: {                          vendors: {                             name: `chunk-vendors` ,                             test: /[\\/]node_modules[\\/]/ ,                              priority: -10 ,                              chunks: 'initial' ,                             enfore: false                           },                         common: {                             name: `chunk-common` ,                             minChunks: 2 ,                             priority: -20 ,                              chunks: 'initial' ,                             reuseExistingChunk: true                           }                     }                 }             }         }     } }; 
Vue-cli3中的默认配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 module .exports = {    configureWebpack:config  =>         return  {             optimization: {                 splitChunks: {                     chunks: 'async' ,                     minSize: 30000 ,                     maxSize: 0 ,                     minChunks: 1 ,                     maxAsyncRequests: 6 ,                     maxInitialRequests: 4 ,                     automaticNameDelimiter: '~' ,                     cacheGroups: {                         vendors: {                             name: `chunk-vendors` ,                             test: /[\\/]node_modules[\\/]/ ,                             priority: -10 ,                             chunks: 'initial'                          },                         common: {                             name: `chunk-common` ,                             minChunks: 2 ,                             priority: -20 ,                             chunks: 'initial' ,                             reuseExistingChunk: true                          }                     }                 }             }         }     } }; 
参考 
vue vue instance vue 模板编译,正则解析 正则解析是真的不好记!!!
输入: render(-, {msg: ‘chendap’, name: ‘wmh’})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function  render (template, data )   var  reg = /\{\{(\w+)\}\}/    if  (reg.test(template)) {     const  name = RegExp .$1. trim()      template = template.replace(reg, data[name])     return  render(template, data)   }   return  template } render(`{{msg}}-{{name}}` , {msg : 'chendap' , name : 'wmh' })  function  transform (word )   return  word.replace(/[-|_|@]([\w])/g , (match, p) => p.toUpperCase()) } 
RegExp 是javascript中的一个内置对象。为正则表达式。RegExp.$1是RegExp的一个属性,指的是与正则表达式匹配的第一个 子匹配(以括号为标志)字符串,以此类推,RegExp.$2,RegExp.$3,..RegExp.$99总共可以有99个匹配
 
实现一个 Observer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 function  Observer (data )   this .data = data   this .walk(data) } Observer.prototype = {   walk(data) {          Object .keys(data).forEach(()  =>       this .defineReactive(data, key, data[key])     })   },   defineReactive(data, key, val) {     let  dep = new  Dep()     let  childObj = observe(val)     Object .defineProperty(data, key, {       enumerable: true ,       configurable: true ,       get : function getter() {         if  (Dep.target) {                      console .log(Dep.target)           dep.addSub(Dep.target)         }         return  val       },       set : function setter() {         if  (newVal === val) {           return          }         val = newVal         childObj = observe(newVal)         dep.notify()       },     })   }, } function  observe (value, vm )   if  (!value || typeof  value !== 'object' ) {     return    }   return  new  Observer(value) } function  Dep (  this .subs = [] } Dep.prototype = {   addSub(sub) {     this .subs.push(sub)   },   notify() {     this .subs.forEach((sub ) =>  {       sub.update()     })   }, } Dep.target = null  
实现一个 Watcher 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function  Watcher (vm, exp, cb )   this .cb = cb   this .vm = vm   this .exp = exp   this .value = this .get()  } Watcher.prototype = {   update() {     this .run()   },   run() {     let  value = this .vm.data[this .exp]     let  oldVal = this .value     if  (value !== oldVal) {       this .value = value       this .cb.call(this .vm, value, oldVal)     }   },   get () {     Dep.target = this       let  value = this .vm.data[this .exp]      Dep.target = null       return  value   }, } 
vuex vue-router Array.prototype.map() 1.不改变原数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var  arr = [1 ,2 ,3 ,4 ,5 ]var  obj = {name : 'cpp' }Array .prototype.mockMap = function (fn, context )   var  arr = Array .prototype.slice.call(this );   var  mapArr = []   for (var  i = 0 ; i< arr.length; i ++) {     mapArr.push(fn.call(context, arr[i], i, this ))   }   return  mapArr } var  test = arr.mockMap(function (e )   console .log(this , 'this指向obj' )   return  e *2  }, obj) 
Array.prototype.filter() 返回过滤后的数组
1 2 3 4 5 6 7 8 9 10 11 12 13 Array .prototype.Filter = function (fn, context )    let  arr = this ;     let  len = arr.length;     let  newArr = [];     for (let  i=0 ; i<len; i++){         if (i in  arr){              if (fn.call(context, arr[i], i, arr)){                 newArr.push(arr[i])             }         }     }     return  newArr; } 
Array.prototype.some() 一旦有一个值满足条件,即能返回true,否则返回false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Array .prototype.mySome = function (fn, context )   var  arr = this    for (let  i = 0 ; i < arr.length; i++) {     if  (i in  arr) {       if  (fn.call(context, arr[i], i, arr)) {         return  true        }     }   }   return  false  } var  arr = [0 ,1 ,0 ,3 ,12 ]var  res = arr.mySome(e  =>3 ) console .log(res) 
Array.prototype.find() 返回当前满足条件的那个数组项
Array.prototype.reduce() 
初始值传不传 差距蛮大 
返回值如何处理1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Array .prototype.mockReduce = function (fn, initialValue )   var  arr = Array .prototype.slice.call(this );   var  res, startIndex   res = initialValue ? initialValue : arr[0 ];   startIndex = initialValue ? 0  : 1 ;   for (var  i = startIndex; i < arr.length; i ++) {     res = fn.call(null , res, arr[i], i, this )   }   return  res } function  add2 (...arr )   return  arr.mockReduce((a, b, i, ar ) =>  {     console .log(a, b, i, arr)     return  a + b;   }) } add2(...[1 ,2 ,3 ,4 ]) 
 
 
Array.prototype.flat() 多维数组降到一维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 function  flatten (arr = [] )   const  stack = [...arr]   const  res = []   while  (stack.length) {     const  next = stack.pop()      if (Array .isArray(next)) {       stack.push(...next)     } else  {       res.push(next)     }   }   return  res.reverse() } function  flatten (arr = [] )   return  arr.redece((prev, cur ) =>  {     return  prev.concat(Array .isArray(cur) ? flatten(cur) : cur)   }, []) } function  flatten (arr = [] )   while (arr.some(Array .isArray)) {     arr = [].concat(...arr)   }   return  arr } flatten([1 , 2 , 3 , [4 ,5 ], 6 ]) 
去重 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var  arr = [1 , 2 , 3 , 3 , 4 , 1 , 00 , 99 ,99 ]function  unique (arr )   return  arr.reduce((prev, cur ) =>  {     if  (!prev.includes(cur)) {       prev.push(cur)     }     return  prev   }, []) } var  test = unique(arr)console .log(tes) function  unique (arr )   return  arr.filter((item, index, arr ) =>  arr.indexOf(item) === index) } 
URLSearchParams url参数解析 1 2 3 4 5 6 7 8 9 10 11 var  str = new  URL('http://ccing.com/develop.html?systemId=111&idc=cc' )function  getParams (url ) 	var  params = new  URLSearchParams(url.search);  	var  obj = {}; 	for  ([k, v] of  params.entries()) { 		obj[k] = v 	} 	return  obj } var  test = getParams(str)console .log(test)
存在缺陷,如果url里含有hash值,会优先解析hash参数,第二种
1 2 3 4 5 6 7 8 9 10 11 12 var  str = 'http://ccuning.com/d.html#/dashboard?reportId=1118&versionId=1.0&systemId=111' function  getParams (url ) 	var  params = url.split('?' ).pop().split('#' ).shift().split('&' ); 	var  obj = {}; 	for  ([k, v] of  params.entries()) { 		const  [key, val] = v.split('=' ) 		obj[key] = val; 	} 	return  obj } var  test = getParams(str)console .log(test)
缓存memorize函数 第一种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var  memorize = function (fn )   const  cache = {}   return  function (...args )      const  _args= JSON .stringify(args)     return  cache[_args] || (cache[_args] = fn.apply(this , args))    } } var  add = function (a, b )     console .log('函数缓存' )     return  a + b; } var  addFn = memorize(add)var  a1 = addFn(2 , 6 )var  a2 = addFn(2 , 6 )console .log(a1, a2)
第二种:
1 2 3 4 5 6 7 8 9 10 const  dataCache = new  Map ()async  getData(url) {  let  key = url   let  data = dataCache.get(key)   if  (!data) {     const  res = await  req.get(url)     dataCache.set(key, data)   }   return  data } 
手写原始AJAX 使用AJAX最主要的两个特性做下列事:
在不重新加载页面的情况下发送请求给服务器。 
接受并使用从服务器发来的数据。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function  makeGetRequest (url, cb )      let  httpRequst = new  XMLHttpRequest();      httpRequest.onreadystatechange = ()  =>          if  (httpRequest.readyState === XMLHttpRequest.done) {              if  (httpRequest.status === 200 ) {         cb(httpRequest.responsText)       }     }   }      httpRequest.open('GET' , url, true )       httpRequest.send();       httpRequset.abort() } 
1 2 3 4 5 6 7 8 9 10 11 12 function  makePostRequest (url, cb, userName )   let  httpRequst = new  XMLHttpRequest();   httpRequest.onreadystatechange = ()  =>     if  (httpRequest.readyState === XMLHttpRequest.done) {       if  (httpRequest.status === 200 ) {         cb(httpRequest.responsText)       }     }   }   httpRequest.open('Post' , url, true );   httpRequest.setRequestHeader('Content-Type' , 'application/x-www-form-urlencoded' );   httpRequest.send('userName='  + encodeURIComponent (userName)); 
 
 
手写jsonp 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function  jsonp (url, callBack )   var  funcName = 'jsonp_'  + Date .now();   const  script = document .createElement('script' )   script.src = url   script.async = true    script.type = 'text/javascript'    document .body.appendChild(script)   window [funcName] = function (data )      callBack && callBack(data)          delete  window [funcName]     document .body.removeChild(script)   } }   jsonp('http://127.0.0.1:8080/api' , function  (res )      console .log(res)   }) 
RGB转16进制 1.| 运算符跟 & 的区别在于如果对应的位中任一个操作数为1 那么结果就是1。
1 2 3 4 5 6 7 8 function  RGBToHex (rgb )   var  rgbArr = rgb.split(/[^\d]+/ );   var  color = rgbArr[1 ] << 16  | rgbArr[2 ] << 8  | rgbArr[3 ];   return  `#${color.toString(16 )} `  } var  test = 'rgb(255,255,255)' console .log(RGBToHex(test))
16进制转RGB 1 2 3 4 5 6 7 8 9 10 function  HexToRgb (hex )   var  hexx = hex.replace('#' , '0x' );   var  r = hexx >> 16 ;   var  g = hexx >> 8  & 0xff ;   var  b = hexx & 0xff ;   return  `rgb(${r} , ${g} , ${b} )`  } var  test = '#ffffff' console .log(HexToRgb(test)) 
实现一下es6的extends 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Parent    constructor (name) {     this .name = name   }   getName() {     return  this .name   } } class  Child  extends  Parent    constructor (name, age) {     super (name)     this .age = age   } } 
手写发布订阅模式 理解vue事件绑定的核心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class  EventEmitter    constructor () {     this .events = {}   }      $on(type, cb) {     if  (!this .events[type]) {       this .events[type] = [cb]     } else  {       this .events.push(cb)     }   }      $emit(type, data) {     if  (this .events[type] && this .events[type].length) {       this .events[type].forEach(fn  =>         fn.call(this , data)       });     }   }      $off(type, cb) {     if  (!this .events[type]) return  false      if  (this .events[type] && type.length) {       this .events[type] = this .events[type].filter(e  =>     } else  if  (type.length) {       this .events[type] = []     } else  {       this .events = {}     }   }      once(type, cb) {     function  fn (       cb()       this .$off(type, fn)     }     this .$on(type, fn)   } } const  event = new  EventEmitter()const  handler = (...rest ) =>  {  console .log(`rest handler` , rest) } event.$on('click' , handler) event.$emit('click' , 1 ,2 ,3 ,4 ) event.$off('click' , handler) event.once("dbClick" , () => {   console .log(123456 ); }); event.$emit("dbClick" ); event.$emit("dbClick" ); 
简单的算法 滑动窗口,无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var  lengthOfLongestSubstring = function (s )     if  (s && !s.length) return  0      let  arr = []     let  max = 0      for (let  i = 0 ; i < s.length; i++) {       const  num = arr.indexOf(s[i])       if (num > -1 ) {         arr.splice(0 , num + 1 )       }       arr.push(s[i])       max = Math .max(max, arr.length)     }     return  max     }; 
计算容器的面积 1 2 3 输入:[1 ,8 ,6 ,2 ,5 ,4 ,8 ,3 ,7 ] 输出:49   解释:图中垂直线代表输入数组 [1 ,8 ,6 ,2 ,5 ,4 ,8 ,3 ,7 ]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49 。 
双指针解法1 2 3 4 5 6 7 8 9 10 11 12 13 14 var  maxArea = function (height )     var  max = 0      var  left = 0      var  right = height.length - 1      while (left < right) {       max = Math .max(max, Math .min(height[right], height[left]) * (right - left))       if  (height[right] > height[left]) {         left ++       } else  {         right --        }     }     return  max }; 
 
 
实现一个带缓存的求阶乘函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 function  factoialIterative (n )   if  (n < 0 ) return  undefined    let  total = 1    for  (let  num = n; num > 1 ; num --) {     total = total * num   }   return  total } function  factorial (n )     if  (n <= 1 ) {       return  1      } else  {       return  n * factorial(n - 1 )     } } var  b = factorial(3 )console .log(b)function  factorial (n )     var  m = new  Map ()     var  fn = (n ) =>  {         if (n <= 1 ) return  1          if (m.has(n)) return  m.get(n)         let  res = n * fn(n - 1 )         m.set(n, res)         return  res     }     return  fn(n) } function  factorialTail (n, total = 1  )   if  (n <= 1 ) return  1    return  factorialTail(n-1 , n * total) } 
实现一个带缓存斐波那契数列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function  fibonacci (n )   if  (n < 1 ) return  0    if  (n <= 2 ) return  1    return  fibonacci(n - 1 ) + fibonacci(n - 2 ) } function  fibonacciMemo (n )   const  memo = [0 , 1 ]   const  fibonacci = (n ) =>  {     if  (memo[n] != null ) return  momo[n]     return  memo[n] = fibonacci(n - 1 , memo) + fibonacci(n - 2 , memo)   }   return  fibonacci(n) } 
LRU Cache 浏览器中的缓存是一种在本地保存资源副本,它的大小是有限的,当我们请求数过多时,缓存空间会被用满,此时,继续进行网络请求就需要确定缓存中哪些数据被保留,哪些数据被移除,这就是浏览器缓存淘汰策略,最常见的淘汰策略有 FIFO(先进先出)、LFU(最少使用)、LRU(最近最少使用)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class  LRUCache {    private  caches: Map<number , number >     private  capacity:number ;     constructor (capacity: number  ) {         this .caches = new  Map()         this .capacity = capacity     }               get (key: number ): number  {         if  (this .caches.has(key)) {             const  val = this .caches.get(key)             this .caches.delete(key)             this .caches.set(key, val)             return  val         }         return  -1      }               put(key: number , value: number ): void  {         if  (this .caches.has(key)) {             this .caches.delete(key)         } else  if  (             this .caches.size >= this .capacity         ) {             this .caches.delete(this .caches.keys().next().value)         }         this .caches.set(key, value)     } } 
验证回文字符串 示例 1:
1 2 3 4 5 6 7 8 9 var  isPalindrome = function (s )     if (typeof  s != 'string' ) return  s = s.toString()     if (s.length < 2 ) return  true      var  r = /[^a-zA-Z0-9]/ig ;     s = s.replace(r, '' ).toLowerCase()     return  s == s.split('' ).reverse().join('' ) }; isPalindrome('cppc' )  
全排列 输入: [1,2,3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var  permute = nums  =>  var  len = nums.length   if  (nums.length < 2 ) return  nums   var  res = []   var  path = []   var  backTrack = (path, nums ) =>  {     if  (path.length === nums.length) {       res.push(path)     }     for  (let  num of  nums) {       if  (!path.includes(num)) {         path.push(num)         backTrack(path.slice(), nums)         path.pop()       }     }   }   backTrack(path, nums)   return  res } permute([1 ,2 ,3 ,4 ]) 
驼峰转换 // 输入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function  camel (str )          let  ans = "" ;     let  upper = false ;     for  (let  index = 0 ; index < str.length; index++) {         const  element = str[index];         if  (element == '_'  || element == '-'  || element == '@' ) {           upper = true ;         } else  {           if  (upper) {             ans += element.toUpperCase();           } else  {             ans += element;           }           upper = false ;         }     }     return  ans; }; function  transform (word )   return  word.replace(/[-|_|@]([\w])/g , (match, p) => p.toUpperCase()) } 
反过来呢,比如ContentType需要转成content-type呢
1 2 3 4 5 6 7 8 下划线转驼峰 function  revserTransform (word, mark = '-'  )   return  word.replace(/([A-Z])/g , `${mark} $1` ).replace(/(\w)+g/ , mark).toLowerCase().slice(1 ) } revserTransform('ContentType' , '@' )  revserTransform('ContentType' , '-' )  
二分法查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function  search (nums: number [], target: number  ): number      let  max = nums.length - 1      let  min = 0      while (max >= min) {         if  (nums[max] === target) {           return  max         }          else  if  (target < nums[max]) {           max --         } else  if  (target > nums[min]){           min ++         }     }     return  -1  }; 
第一家公司就跪了,这道题铭记在心
 
反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 var  l2 = {  val: 1 ,   next: {     val: 2 ,     next: {       val: 3 ,       next: {         val: 4 ,         next: {           val: 5 ,           next: null          }       }     }   } } function  reverse (head )   let  cur = head   let  pre = null    let  next = null    while (current) {     next = cur.next     cur.next = pre     pre = cur     cur = next   }   return  pre } 
删除链表的节点 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
来源:力扣(LeetCode)https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function  deleteNode (head, val )   if  (head.val === val) return  head.next   let  pre = head;   while (head.next) {     if (head.next.val == val) {       head.next = head.next.next       return  pre     }     head = head.next   }   return  head }; var  head = {  val: 4 ,   next: {     val: 5 ,     next: {       val: 1 ,       next: {         val: 9 ,         next: null        }     }   } } deleteNode(head, 1 ) 
合并俩个有序链表 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
来源:力扣(LeetCode)https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof 
1 2 3 4 5 6 7 8 9 10 11 12 13 function  mergeTwoLists (l1, l2 )   if  (!l1) {     return  l2   } else  if  (!l2) {     return  l2   } else  if  (l1.val < l2.val) {     l1.next = mergeTwoLists(l1.next, l2)     return  l1   } else  {     l2.next = mergeTwoLists(l2.next, l1)     return  l2   } } 
最大子序和 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function  maxSubArray (nums )   let  ans = nums[0 ]   let  sum = 0    for  (let  num of  nums) {     if  (sum > 0 ) {       sum = sum + num     } else  {       sum = num     }     ans = Math .max(ans, sum)   }   return  ans } var  nums = [-2 ,1 ,-3 ,4 ,-1 ,2 ,1 ,-5 ,4 ]maxSubArray(nums)  
参考链接 
感谢各位大佬的倾情奉献,小弟只是代码搬运工!