API实现
jQuery offset 实现递归实现通过 getBoundingClientRect API 实现
数组 reduce 方法的相关实现概念reduce的用法简单用法:计算数组中每个元素出现的次数:数组去重:将二维数组转化为一维:将多维数组转化为一维:
reduce 实现 runPromiseInSequencereduce 实现 pipe实现一个reduce
compose 实现的几种方案compose 概念面向过程的实现方式reduce的实现方式Promise的实现方式
本文总结于:
侯策《前端开发核心知识进阶》
jQuery offset 实现
offset() 方法返回或设置匹配元素相对于文档的偏移。
递归实现
const offset = ele
=> {
let result
= {
top
: 0,
left
: 0
}
const getOffset = (node
) => {
if (node
.nodeType
!== 1) {
return
}
position
= window
.getComputedStyle(node
)['position']
if (position
=== 'static') {
getOffset(node
.parentNode
)
return
}
result
.top
= node
.offsetTop
+ result
.top
- node
.scrollTop
result
.left
= node
.offsetLeft
+ result
.left
- node
.scrollLeft
if (position
=== 'fixed') {
return
}
getOffset(node
.parentNode
)
}
if (window
.getComputedStyle(ele
)['display'] === 'none') {
return result
}
let position
getOffset(ele
)
return result
}
let box
= document
.getElementById('box2')
let result
= offset(box
);
console
.log(result
)
通过 getBoundingClientRect API 实现
const offset = ele
=> {
let result
= {
top
: 0,
left
: 0
}
if (!ele
.getClientRects().length
) {
return result
}
if (window
.getComputedStyle(ele
)['display'] === 'none') {
return result
}
result
= ele
.getBoundingClientRect()
var docElement
= ele
.ownerDocument
.documentElement
return {
top
: result
.top
+ window
.pageYOffset
- docElement
.clientTop
,
left
: result
.left
+ window
.pageXOffset
- docElement
.clientLeft
}
}
数组 reduce 方法的相关实现
概念
arr
.reduce(callback
,[initialValue
])
callback (执行数组中每个值的函数,包含四个参数)
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)
initialValue (作为第一次调用 callback 的第一个参数。) 如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
reduce的用法
简单用法:
var arr
= [1, 2, 3, 4];
var sum
= arr
.reduce((x
,y
)=>x
+y
)
var mul
= arr
.reduce((x
,y
)=>x
*y
)
console
.log( sum
);
console
.log( mul
);
计算数组中每个元素出现的次数:
let names
= ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum
= names
.reduce((pre
,cur
)=>{
if(cur
in pre
){
pre
[cur
]++
}else{
pre
[cur
] = 1
}
return pre
},{})
console
.log(nameNum
);
数组去重:
let arr
= [1,2,3,4,4,1]
let newArr
= arr
.reduce((pre
,cur
)=>{
if(!pre
.includes(cur
)){
return pre
.concat(cur
)
}else{
return pre
}
},[])
console
.log(newArr
);
将二维数组转化为一维:
let arr
= [[0, 1], [2, 3], [4, 5]]
let newArr
= arr
.reduce((pre
,cur
)=>{
return pre
.concat(cur
)
},[])
console
.log(newArr
);
将多维数组转化为一维:
var result
= [
{
subject
: 'math',
score
: 10
},
{
subject
: 'chinese',
score
: 20
},
{
subject
: 'english',
score
: 30
}
];
var sum
= result
.reduce(function(prev
, cur
) {
return cur
.score
+ prev
;
}, 0);
console
.log(sum
)
reduce 实现 runPromiseInSequence
const f1 = () => {
console
.log('p1 running')
}
const f2 = () => {
console
.log('p2 running')
}
const array
= [f1
, f2
]
const runPromiseInSequence = (array
, value
) => array
.reduce(
(promiseChain
, currentFunction
) => promiseChain
.then(currentFunction
),
Promise
.resolve(value
)
)
runPromiseInSequence(array
, 'init')
reduce 实现 pipe
function pipe(src
, ...fns
){
return fns
.reduce(function(fn1
, fn2
){
return fn2(fn1
)
}, src
);
}
实现一个reduce
if (!Array
.prototype
.reduce
) {
Object
.defineProperty(Array
.prototype
, 'reduce', {
value
: function(callback
) {
if (this === null) {
throw new TypeError( 'Array.prototype.reduce ' +
'called on null or undefined' )
}
if (typeof callback
!== 'function') {
throw new TypeError( callback
+
' is not a function')
}
var o
= Object(this)
var len
= o
.length
>>> 0
var k
= 0
var value
if (arguments
.length
>= 2) {
value
= arguments
[1]
} else {
while (k
< len
&& !(k
in o
)) {
k
++
}
if (k
>= len
) {
throw new TypeError( 'Reduce of empty array ' +
'with no initial value' )
}
value
= o
[k
++]
}
while (k
< len
) {
if (k
in o
) {
value
= callback(value
, o
[k
], k
, o
)
}
k
++
}
return value
}
})
}
其中x>>>0,保证x有意义(为数字类型),且为正整数,在有效的数组范围内(0 ~ 0xFFFFFFFF),且在无意义的情况下缺省值为0 forEach实现:
Array
.prototype
.reduce
= Array
.prototype
.reduce
|| function(func
, initialValue
) {
var arr
= this
var base
= typeof initialValue
=== 'undefined' ? arr
[0] : initialValue
var startPoint
= typeof initialValue
=== 'undefined' ? 1 : 0
arr
.slice(startPoint
)
.forEach(function(val
, index
) {
base
= func(base
, val
, index
+ startPoint
, arr
)
})
return base
}
compose 实现的几种方案
compose 概念
compose 的参数是函数数组,返回的也是一个函数
compose 的参数是任意长度的,所有的参数都是函数,执行方向是自右向左的,因此初始函数一定放到参数的最右面compose 执行后返回的函数可以接收参数,这个参数将作为初始函数的参数,所以初始函数的参数是多元的,初始函数的返回结果将作为下一个函数的参数,以此类推。因此除了初始函数之外,其他函数的接收值是一元的compose 其实和前面提到的 pipe 一样,就是执行一连串不定长度的任务(方法) ,实际上,compose 和 pipe 的差别只在于调用顺序的不同:
fn1(fn2(fn3(fn4(args
))))
fn4(fn3(fn2(fn1(args
))))
面向过程的实现方式
const compose = function(...args
) {
let length
= args
.length
let count
= length
- 1
let result
return function f1 (...arg1
) {
result
= args
[count
].apply(this, arg1
)
if (count
<= 0) {
count
= length
- 1
return result
}
count
--
return f1
.call(null, result
)
}
}
reduce的实现方式
const reduceFunc = (f
, g
) => (...arg
) => g
.call(this, f
.apply(this, arg
))
const compose = (...args
) => args
.reverse().reduce(reduceFunc
, args
.shift())
Promise的实现方式
const compose = (...args
) => {
let init
= args
.pop()
return (...arg
) =>
args
.reverse().reduce((sequence
, func
) =>
sequence
.then(result
=> func
.call(null, result
))
, Promise
.resolve(init
.apply(null, arg
)))
}
参考资料:
https://blog.csdn.net/zwkkkk1/article/details/80229923
https://www.jianshu.com/p/e375ba1cfc47