Array.prototype.map 1 2 3 [1 ,2 ]._map (i => i * 2 ) [2 ,4 ]
mdn 里的 map
1 2 map (function (element, index, array ) { }, thisArg)
1 2 3 4 5 6 7 8 9 10 11 Array .prototype ._map = function (fn ) { if (typeof fn !== 'function' ) return const array = this const newArray = [] for (let i = 0 ; i < array.length ; i++) { newArray.push (fn.call (arguments [1 ], array[i], i, array)) } return newArray }
Array.prototype.filter 和 map 没什么区别
1 2 3 [1 ,2 ]._filter (i => i>1 ) [2 ]
1 2 3 4 5 6 7 8 9 10 11 Array .prototype ._filter = function (fn ) { if (typeof fn !== 'function' ) return const array = this const newArray = [] for (let i = 0 ; i < array.length ; i++) { if (fn.call (arguments [1 ], array[i], i, array)) { newArray.push (array[i]) } } return newArray }
Array.prototype.reduce 1 2 3 [1 ,2 ,3 ]._reduce ((left, right ) => left + right)6
mdn
1 reduce (function (previousValue, currentValue, currentIndex, array ) { }, initialValue)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Array .prototype ._reduce = function (fn ) { if (typeof fn !== 'function' ) return const array = this let flag if (arguments [1 ]) { preValue = arguments [1 ] flag = true } else { preValue = array[0 ] flag = false } for (let i = flag ? 0 : 1 ; i < array.length ; i++) { preValue = fn (preValue, array[i], i, array) } return preValue }
Object.create 创建一个新对象,使用现有的对象来作为新创建对象的原型
1 2 3 4 5 6 7 const _objectCreate = proto => { if (typeof proto !== 'object' || proto === null ) return function fn ( ) {} fn.prototype = proto return new fn () }
Function.prototype.call 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Function .prototype .myCall = function (context ) { let context = context || window context.fn = this ; let args = [...arguments ].slice (1 ) let result = context.fn (...args) delete context.fn return result }
Function.prototype.bind 1 2 3 4 5 6 7 8 9 10 11 12 13 Function .prototype .myBind = function (context ) { if (typeof this !== 'function' ) throw new TypeError ('Error' ) let fn = this let args = [...arguments ].slice (1 ) return function F ( ) { if (this instanceof F) { return new fn (...args, ...arguments ) } return fn.apply (context, [...args, ...arguments ]) } }
new 实例化 1 2 3 4 5 6 7 8 9 function Person (name, age ) { this .name = name; this .age = age; }Person .prototype .getName = function ( ) { return this .name }let p = _new (Person , "sillywa" , 23 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function _new ( ) { let obj = {} let [Con , ...args] = arguments obj.__proto__ = Con .prototype let res = Con .call (obj, ...args) return res instanceof Object ? res : obj }
instanceof 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function myInstanceof (left, right ) { let p = Object .getPrototypeOf (left) let prototype = right.prototype while (p) { if (p === prototype) return true p = Object .getPrototypeOf (p) } return false }console .log (myInstanceof (5 , Number ));console .log (myInstanceof (5 , Object ));console .log (myInstanceof (5 , String ));console .log (5 instanceof Number );console .log (5 instanceof Object );console .log (new Number (5 ) instanceof Number );console .log (new Number (5 ) instanceof Object );
==扁平数据结构转Tree== 总的来说就两步:
创建当前 id 的 map
将当前 id 的 map 放入 pid 的 map 的 children 中
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 let arr = [ {id : 1 , name : '部门1' , pid : 0 }, {id : 2 , name : '部门2' , pid : 1 }, {id : 3 , name : '部门3' , pid : 1 }, {id : 4 , name : '部门4' , pid : 3 }, {id : 5 , name : '部门5' , pid : 4 }, ]function arrayToTree (arr ) { const result = [] const map = {} arr.forEach ((item, index ) => { const { id, pid } = item if (!map[id]) { map[id] = { children : [], } } map[id] = { ...item, children : map[id]['children' ] } const treeItem = map[id] if (pid === 0 ) { result.push (treeItem) } else { if (!map[pid]) { map[pid] = { children : [] } } map[pid].children .push (treeItem) } }) return result }
只执行一次的 once 实现一个 once 函数,记忆返回结果只执行一次
类似于 lodash.once
1 2 3 4 5 6 7 8 9 10 const f = (x ) => x;const onceF = once (f);console .log (onceF (3 ))console .log (onceF (100 ))
1 2 3 4 5 6 7 8 9 10 11 function once (f ) { let result let flag = false return (...args ) => { if (flag) return result result = f (...args) flag = true return result } }
无限累加的 sum 参数无限,调用次数无限
1 2 3 4 5 sum (1 , 2 , 3 ).valueOf (); sum (2 , 3 )(2 , 4 ).valueOf (); sum (1 )(2 )(3 )(4 ).valueOf (); sum (2 )(4 , 1 )(2 ).valueOf (); sum (1 )(2 )(3 )(4 )(5 )(6 ).valueOf ();
1 2 3 4 5 function sum (...args ) { const f = (...rest ) => sum (...args, ...rest) f.valueOf = () => args.reduce ((x, y ) => x + y, 0 ) return f }
用于函数合成的 compose 实现一个 compose 函数,进行函数合成,比如 redux 中的 compose,react 高阶组件连续调用时的 compose
1 2 3 4 5 6 const add10 = (x ) => x + 10 ;const mul10 = (x ) => x * 10 ;const add100 = (x ) => x + 100 ;compose (add10, mul10, add100)(10 );
错误的(我最初写的)
1 2 3 4 5 6 7 8 9 10 function compose ( ) { const funcs = Array .from (arguments ).reverse () const n = funcs.length return (num ) => { for (let i = 0 ; i < n; i++) { num = funcs[i](num) } return num } }
显然没有考虑函数的参数个数与返回值个数的问题,只用了一个num,默认一个参数了。
正确版
利用 array.reduce 函数
上一次的返回结果会作为下一次的参数,a 为上一个值,b为当前值
1 2 3 function compose (...funcs ) { return funcs.reduce ((a,b ) => (...args ) => a (b (...args))) }
是一个正向的,从左向右递推的过程。
如果 a 是函数,b是参数,就是 (a,b) => a(b)
但是要考虑到 b 也是函数,所以 b 也得调用一下,得到返回值后再作为 a 的参数传入
格式化时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function dateFormat (date ) { let year = date.getFullYear () let month = showTime (date.getMonth () + 1 ) let day = showTime (date.getDay ()) let hours = showTime (date.getHours ()) let minutes = showTime (date.getMinutes ()) let second = showTime (date.getSeconds ()) const str = `${year} -${month} -${day} -${hours} -${minutes} -${second} ` return str }function showTime (t ) { let time time = t > 10 ? t : '0' + t return time }console .log (dateFormat (new Date (Date .now ())))