Cytoscape.js 集合 every() 方法详解:全量条件校验与源码级剖析
2026/9/23 17:51:31 网站建设 项目流程

Cytoscape.js 集合 every() 方法详解:全量条件校验与源码级剖析

【免费下载链接】cytoscape.jsGraph theory (network) library for visualisation and analysis项目地址: https://gitcode.com/gh_mirrors/cy/cytoscape.js

every()是 Cytoscape.js 中集合(collection)对象提供的全量谓词校验方法:它遍历集合中的每一个元素,只有当所有元素都满足回调函数(或条件)时才返回true。它在图数据校验、筛选前置判断、布局/样式批量操作前的条件检查等场景中非常实用,本文结合仓库源码与测试用例,深入讲解其用法、回调参数、边界行为以及与some()allAre()等兄弟方法的异同。

一、核心用法与官方示例

eles.every( fn )对集合eles中的每个元素依次调用回调函数fn,只要有一个元素令fn返回假值(false),就立即返回false并停止遍历;只有全部元素都返回真值,最终才返回true

原文档给出了如下示例(见 every.md):

var jAndE = cy.$('#j, #e'); var everyHeavierThan50 = jAndE.every(function( ele ){ return ele.data('weight') > 50; }); console.log( 'every heavier than 50 ? ' + everyHeavierThan50 );

这里先用选择器'#j, #e'通过cy.$()取回 id 分别为je的两个元素组成集合,然后检查这两个元素的weight数据是否全部大于 50。只要其中一个元素的weight <= 50,结果即为false

回调函数的三个参数

与原生数组的Array.prototype.every一致,Cytoscape.js 的回调会收到三个参数:

参数含义
ele当前遍历到的元素(node 或 edge)
i当前元素在集合中的索引(从 0 开始)
eles正在遍历的整个集合对象

这一点有测试用例直接验证(见 collection-comparison.mjs):

it('eles.every()', function(){ expect( cy.edges().every(function( ele, i, eles ){ expect( is.elementOrCollection(ele) ).to.be.true; expect( is.elementOrCollection(eles) ).to.be.true; expect( is.number(i) ).to.be.true; return ele.data('source') === 'n1'; }) ).to.be.false; expect( cy.edges().every(function( ele, i, eles ){ expect( is.elementOrCollection(ele) ).to.be.true; expect( is.elementOrCollection(eles) ).to.be.true; expect( is.number(i) ).to.be.true; return ele.isEdge(); }) ).to.be.true; });

该测试在beforeEach中初始化了 3 个节点(n1n2n3)和 2 条边(n1n2n2n3):

  • 第一条断言:因为并非所有边的source都是n1n2n3的 source 是n2),所以返回false
  • 第二条断言:两条边全部满足ele.isEdge(),所以返回true

返回值语义

  • 所有元素都满足条件 → 返回true
  • 任意一个元素不满足条件 → 立即短路返回false
  • 空集合→ 从实现逻辑看,循环体一次都不执行,直接返回true(数学上的"全称命题对空集成立"语义),这是从源码结构可直接推断的行为。

二、源码级实现原理

every()定义在集合比较模块中,见 comparators.mjs:

every: function( fn, thisArg ){ for( let i = 0; i < this.length; i++ ){ let ret = !thisArg ? fn( this[ i ], i, this ) : fn.apply( thisArg, [ this[ i ], i, this ] ); if( !ret ){ return false; } } return true; },

关键实现细节:

  1. 基于下标循环:Cytoscape.js 的集合对象继承了Array.prototype(见 index.mjs),元素通过this[i]按下标直接访问,因此every()本质上就是对集合内部数组做一次线性扫描,时间复杂度为 O(n)(最坏情况)。
  2. 短路求值:一旦某个元素令回调返回假值,立即return false,不再继续遍历,适合对大型图做快速失败校验。
  3. 可选的thisArg:第二个参数用于绑定回调内部的this上下文。不传时直接以fn( this[i], i, this )形式调用;传入时通过fn.apply( thisArg, [ this[i], i, this ] )显式指定this
  4. 回调返回值判定:使用if( !ret )判断,因此回调返回0nullundefined''等任何假值时都会导致结果为false,返回任意真值则继续。

该模块通过util.extend( elesfn, props )挂载到集合原型(见 index.mjs),且由于元素(Element)与集合共享同一原型,单个元素同样可以直接调用ele.every(...)

三、实用场景示例

1. 校验图中所有节点都已定位

var allPositioned = cy.nodes().every(function( node ){ return node.position().x != null && node.position().y != null; }); if( allPositioned ){ console.log('所有节点都有明确坐标,可以执行布局或导出'); }

2. 校验边数据完整性后再运行图算法

var cy = window.cy; var edgesReady = cy.edges().every(function( edge ){ return typeof edge.data('weight') === 'number' && edge.data('weight') > 0; }); if( edgesReady ){ var result = cy.elements().dijkstra( { root: '#n1', weight: function( ele ){ return ele.data('weight'); } } ); // 继续使用最短路径结果…… }

3. 与选择器结合,先取子集再校验

var selectedNodes = cy.$('node:selected'); var allSelectedLocked = selectedNodes.every(function( node ){ return node.locked(); }); if( allSelectedLocked ){ console.log('所有选中节点都处于锁定状态'); }

四、与some()allAre()等方法的对比

在同一个 comparators.mjs 模块中,还定义了语义互补的系列方法:

方法语义返回true的条件说明
every( fn )全量满足所有元素满足fn本文主角,短路于首个失败元素
some( fn )存在满足至少一个元素满足fn短路于首个成功元素,见 some.md
allAre( selector )全量匹配选择器所有元素都匹配选择器基于every()实现:return this.every(function( ele ){ return selObj.matches( ele ); })(见 comparators.mjs),见 allAre.md
is( selector )存在匹配选择器至少一个元素匹配选择器基于some()实现(见 comparators.mjs),见 is.md

从源码可以清晰地看到,allAre是"用选择器写法的 every",is是"用选择器写法的 some"。选择器版本更简洁,但灵活性低于回调版本——回调可以访问元素数据(ele.data())、坐标(ele.position())、样式(ele.style())等运行时信息,而选择器只能基于既有的数据字段、类名、状态等结构化属性。

典型组合用法:cy.elements().every(...)判断全图;cy.$('#a, #b').some(...)判断子集。例如在 collection-comparison.mjs 的allAre测试中,cy.$('#n1, #n2').allAre('node')true,而cy.$('#n1, #n1n2').allAre('node')因混入了边而返回false——这与every的"全量满足"语义完全一致。

五、注意事项与最佳实践

  1. 条件函数中的return不要遗漏every()依赖回调返回值做判断,回调体若漏写return会返回undefined(假值),导致结果恒为false
  2. 空集合返回true:对cy.collection()等空集合调用every()会直接得到true,在业务逻辑中若需要"非空且全部满足",应先判断eles.length > 0或使用eles.nonempty()
  3. 避免在回调中修改集合:遍历期间修改集合元素可能导致索引错位,建议先用eles.filter()eles.remove()等操作生成新集合后再校验。
  4. thisArg用法:当回调是对象方法时,可用eles.every( obj.check, obj )形式绑定this,便于复用校验逻辑。
  5. 性能everysome均具备短路特性,在校验大型图时比"先filter()再比长度"的方式更高效,因为失败时不必扫描完整个集合。

结语

every()是 Cytoscape.js 集合 API 中最基础也最常用的"全量校验"入口,其实现简洁、语义清晰,并与some()allAre()is()构成完整的谓词校验矩阵。无论是做数据完整性检查、图算法前置条件判断,还是交互场景中的状态汇总,它都能以可读、可维护的方式表达"是否全部满足"这一逻辑。更多集合方法与示例可参考 collection 文档目录 及对应的单元测试 collection-comparison.mjs。

【免费下载链接】cytoscape.jsGraph theory (network) library for visualisation and analysis项目地址: https://gitcode.com/gh_mirrors/cy/cytoscape.js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询