Preparation Code Preparation HTML (this will be inserted in the <body>
of a valid HTML5 document in standards mode) (useful when testing DOM operations or including libraries)
Setup JS
function Link (BaseClass = class {} ) {
return class Link extends BaseClass {
next = null ;
prev = null ;
circular = false ;
insertAfter (link ) {
link.unlink ();
const next = this .next ;
this .next = link;
link.prev = this ;
link.next = next;
if (next)
next.prev = link;
}
unlink ( ) {
const nextLink = this .next ;
const prevLink = this .prev ;
this .next = this .circular ? this : null ;
this .prev = this .circular ? this : null ;
if (prevLink) prevLink.next = nextLink;
if (nextLink) nextLink.prev = prevLink;
}
forEach (fn ) {
let link = startLink
for (let i = 0 , l = 100000 ; i < l; i += 1 ) {
link
fn (link)
link = link.next
}
}
*links (forward = true , check = true ) {
let link = this ;
let next;
let prev;
let i = 0 ;
do {
if (!link)
throw new NonCircularError ();
next = link.next ;
prev = link.prev ;
yield [link, i++];
} while ((link = forward ? next : prev) != this && (this .circular ? check || (!check && link) : link));
}
*linksReverse (check = true ) {
yield * this .links (false , check);
}
[Symbol .iterator ]() {
return this .iteratorCached ();
}
iteratorCached ( ) {
let link = this ;
let i = 0 ;
const iteratorResult = { done : false , value : link };
return {
[Symbol .iterator ]() {
return this ;
},
next : () => {
if (!link || (i !== 0 && link === this )) {
if (!link && this .circular )
throw new NonCircularError ();
iteratorResult.done = true ;
iteratorResult.value = undefined ;
return iteratorResult;
}
iteratorResult.value = link;
link = link.next ;
i++;
return iteratorResult;
},
};
}
iterator ( ) {
let link = this ;
let i = 0 ;
return {
[Symbol .iterator ]() {
return this ;
},
next : () => {
if (!link || (i !== 0 && link === this )) {
if (!link && this .circular )
throw new NonCircularError ();
return { done : true , value : undefined };
}
const value = link;
link = link.next ;
i++;
return { done : false , value };
},
};
}
};
}
class NonCircularError extends Error {
constructor ( ) {
super ('Expected linked list to be circular.' );
}
}
class MyLink extends Link () {
next = this
prev = this
circular = true
}
let lastLink
for (const _ of Array .from ({length : 100000 })) {
const link = new MyLink ()
lastLink?.insertAfter (link)
lastLink = link
}
const startLink = lastLink.next
Teardown JS