导言
差不多所有的 js 库都会对原生的 js 和 DOM 模型进行封装和扩展, jQuery 、 prototype 、 Ext 都有类似做法。
由于这些原生对象的相关方法注定会被大量地调用,对它们扩展得好与不好会直接关系到整个类库整体的性能。
经常看到有人说 Ext 的执行效率低下,笔者有时也有这种感觉,点个鼠标好像要延迟一下才有反应。但是说话得要有根据不是,不知道慢在哪里也不能跟着瞎起哄。(当然,也免得文章发出来被别人拍板砖,已经被拍过几次,汗啊 … )。
前一部分文章说了一下怎么用 VML 直接在网页上绘图,并且封装了一个小工具。这一部分的内容就先来看一下 Ext 对 js 的原生对象是如何封装和扩展的。
概览
从截图可以看到,在 Ext.js 这个文件中, Ext 对 Function 、 String 、 Number 、 Array 、 Date 。五个原生对象进行了扩展。这一篇先来分析一下对 Array 对象的扩展,并提出一个小小的疑惑。
Array 对象
js 的原生 Array 对象包含一个 length 属性和 12 个方法,简表如下:
concat() :添加元素
join() :将数组中的元素连接成一个字符串并返回
pop() :弹出最后一个元素
push(): 把一个元素加到数组最后
reverse(): 颠倒顺序
shift(): 移除第一个元素
slice() :返回子数组
splice(): 插入、删除或替换一个元素
toLocaleString(): 把数组转换成一个本地化的字符串
toString() :把数组转化成一个字符串
unshift() :在数组头部插入一个字符串
以上引自《 JavaScript 权威指南 第五版》,加粗部分是自己对照英文版的的翻译,原来的翻译是“把数组转换成一个局部字符串 ”,意思非常模糊,让人搞不懂。顺便再罗嗦一下,第五版的翻译不知道是干什么吃的,很多的东西不翻译或者直译,漏洞百出,建议想买这本书的人不要买这个版本。
在 Ext.js 里给 Array 对象扩展了两个方法,代码如下(注释已经翻译成中文):
Ext.applyIf(Array.prototype, {
/**
* 查找数组中是否存在指定的对象
* @param {Object} 需要查找的对象(的引用)
* @return {Number} 对象在数组中的位置下标 ( 如果不存在该对象,返回 -1)
*/
indexOf : function(o){
// 注意这里:是简单的线性查找,拿数组中的元素一个一个地去对比。
for (var i = 0, len = this.length; i < len; i++){
if(this[i] == o) return i;
}
return -1;
},
/**
* 从数组中删除指定的元素,如果该元素不存在,则什么事情都不做。
* @param {Object} o 需要删除对象的引用
* @return {Array} 返回删除后的数组
*/
remove : function(o){
var index = this.indexOf(o);
if(index != -1){
this.splice(index, 1);
}
return this;
}
});
在注释里面加注意的地方说到 indexOf() 方法的查找问题,可以看到,这里的 indexOf() 使用的是简单的线性查找, remove() 方法调用了这个 indexOf() 方法来查找对象在数组中的位置。这个地方的效率很低,也就是说,如果我们往一个数组里面保存了很多的对象,然后在另外的地方频繁调用数组的 indexOf() 或者 remove() 方法的时候,速度就会比较慢。所以有人老说 Ext 存在效率问题,我想,这个所谓的“效率问题”不是哪一处地方造就的,而是由诸多效率差的小细节积累而成的,假如我们实在没有办法去改变什么,那么至少要注意到这些地方,避免陷阱,这是这篇文的主旨所在。
由于线性查找效率是 O(n) ,所以,在数据量稍大的时候,需要寻找替代 Array 的办法。有很多文章说过关于 Array 的这个问题,包括《权威指南》,办法是模拟一个 Hash 表。基本的思路如下:
var mp={};
mp['key1']={name:'damoqiongqiu',age:'25',QQ:'88403922'};
mp['key2']={name:'damoqiongqiu',age:'26',QQ:'88403922'};
alert(mp.key2.name);
这样处理,可以提升查找效率,效率可能接进 O(1) 。(顺便说一句,效率只能接进是 O(1) ,因为 js 内部通过这个字符串型的 key 去找到 value 也是需要花时间的,即使是通过类似Java或C++的Hash算法,也是需要通过key来算HashCode的不是?通过HashCode找到对应的Hash桶之后还是一个线性查找。)
《指南》里面还有提到一种伪数组:
var a={}
while(i<10){
a[i]=i*I;
i++
}
a.length=i;
如果情况比较好,事先知道插入的元素是有序的就可以使用其它的查找算法,像二分查找之类的,这样的情况估计不容易遇到,除非上天恩赐 J ,否则还讨论个什么劲?
当然,有些情况必须用到数组,除此没有办法,那还有什么好说的,用呗!但是,在确确实实对效率有很多要求的地方,需要考虑类似的变通方法。
一个疑惑:
经常看到有人问, js 里面的 == 和 === 有什么区别,翻了一下书,大概的意思是:
=== 是比较两个值是不是完全相等。
而如果用 == 来比较,假如两个值是同一类型,就用 === 比较它们是否等同。否则如果两个值是以下组合时,将非 Number 型强转成 Nunber 再来比较。
String 、 Number
Number 、 Boolean
也就是说, ”1”==true 是正确的, 1==true 也是正确的,如此这般。
如果一个值是对象,另一个值是 String 时,将对象转成 String ,再来比较这两个 String 是不是相等。
OK ,有了上面的简单解释,我们来测试一下 Ext 中 Array 的 indexOf() 方法。
首先来个简单的:
Ext.onReady(function(){
// 基础语义测试
var test="1";
alert(test==true);
})
没有问题,出来一个 true 。
再来个稍微复杂点的,先向数组里面插入 1000 个对象,然后在第六个元素放一个布尔型的 true 值,然后自己来遍历数组,看看有没有元素和字符型的 ’1’ 相等:
Ext.onReady(function(){
// 自定义数组测试
var test="1";
var arr=[];
for(var i=0;i<1000;i++){
var temp=(i==5)?true:{id:i};
arr.push(temp)
}
for (var i = 0, len = arr.length; i < len; i++){
if(arr[i] ==test){
alert(i);
break;
}
}
})
好,没有问题,找到了第六个元素。
来测 Array 的 indexOf() 方法,从 Ext 的源码里面可以看到, Array 的 indexOf() 方法和我们上面自己遍历的方法是一样的,但是,神奇的事情发生了,看代码:
Ext.onReady(function(){
// 自定义数组测试
var test="1";
var arr=[];
for(var i=0;i<1000;i++){
var temp=(i==5)?true:{id:i};
arr.push(temp)
}
// 测试 Ext 封装 Array 的 indexOf() 方法
alert(arr.indexOf(test));
})
按道理来说,这里也应该能够弹出来元素的位置,但是,结果是,没有找到这个元素。。。可视,这是为什么呢?期待牛人给出解释,不甚感谢!
这个问题已解决,多谢zbm2001的解释,我自己又测试了一下,只有FireFox实现了Array原生的indexOf()方法,而IE、Safari、Opera都没有原生实现。Ext在扩展的时候用的是applyIf()方法,所以在存在原生实现的时候不会拿Ext的实现去覆盖。
分享到:
相关推荐
opencv_python-4.1.0.25-cp37-cp37m-linux_armv7l.whl
onnxruntime-1.13.1-cp38-cp38-win_amd64.whl
Few-shot CIFAR100数据集,来自CIFAR100数据集。 数据集共包含100类别,每个类别600张图像,合计60,000张图像。 数据集介绍:分为训练集、验证集、测试集 --data--train--:60个文件夹,36,000张图片 --data--val--: 20个文件夹,12,000张图片 --data--test--:20个文件夹,12,000张图片 FC100按照超类(Superclass)进行划分:训练集60个超类,验证集20个超类,测试集20个类别。
numpy-1.19.5-cp39-cp39-linux_armv7l.whl
基于springboot的城乡商城协作系统源码数据库文档.zip
基于springboot宠物管理系统源码数据库文档.zip
基于springboot餐饮连锁店管理系统源码数据库文档.zip
基于springboot在线问诊系统源码数据库文档.zip
1、资源内容地址:https://blog.csdn.net/2301_79696294/article/details/143734777 2、数据特点:今年全新,手工精心整理,放心引用,数据来自权威,且标注《数据来源》,相对于其他人的控制变量数据准确很多,适合写论文做实证用 ,不会出现数据造假问题 3、适用对象:大学生,本科生,研究生小白可用,容易上手!!! 4、课程引用: 经济学,地理学,城市规划与城市研究,公共政策与管理,社会学,商业与管理
功能说明: 陕理工图书馆管理系统包括两种用户,管理员,和学生用户。不同的用户都需要进行登录,然后针对其操作权限才能进入管理系统。 系统的设计将分为后台和前台,后台是系统管理员进行登录后管理,前台是学生使用的部分。 前台实现的功能包括:学生用户注册、登录,座位信息查看、阅览室信息、在线交流、座位预约、查看图书位置等。 服务器后台管理实现的功能包括:管理员登录,阅览室信息管理,座位管理,预约管理,图书管理以及用户管理等。 环境说明: 开发语言:python Python版本:3.6.8 数据库:mysql 5.7数据库工具:Navicat11开发软件:pycharm
numpy-1.16.1-cp35-cp35m-linux_armv7l.whl
scipy-1.2.0-cp35-cp35m-linux_armv7l.whl
opencv_python-4.0.1.24-cp37-cp37m-linux_armv7l.whl
ASP.NET酒店管理系统源码(WPF) 一、源码特点 采用WPF进行开发的酒店管理系统源码,界面相当美观,功能齐全 二、菜单功能 1、预订登记:可选择入住时间、离店时间、所在城市、证件类型,保存、删除、查询、返回 2、住宿结算:新增入住、保存、删除、查询、返回 3、今日盘点:查询、返回 4、查询统计: 5、房间管理:增加房间类型、删除类型、增加房间、删除房间、保存、返回 6、用户管理:增加用户、删除用户、保存、返回 7、系统配置:基本功能 8、显示当前系统时间等功能的实现
基于springboot的c语言学习辅导网站源码数据库文档.zip
基于springboot医疗废物管理系统源码数据库文档.zip
opencv_python-4.5.5.64-cp39-cp39-linux_armv7l.whl
gee_python基于机器学习ML(随机森林RF)的土地分类.ipynb
ta_lib-0.5.1-cp310-cp310-win32.whl
内容概要:本文档详细介绍了全国大学生电子设计竞赛的相关信息,包括竞赛的目的、流程、内容和技术要求等。竞赛涵盖了电子电路设计、嵌入式系统开发、信号处理等多个领域,通过竞赛可以有效提升学生的实践动手能力、创新意识和团队协作能力。 适合人群:准备参加全国大学生电子设计竞赛的学生及教师。 使用场景及目标:帮助学生和教师全面了解比赛的要求和流程,为备赛做好充分准备。 其他说明:文中提供了详细的竞赛内容介绍、技术要求、评审标准和注意事项,有助于参赛队伍制定合理的参赛策略,提高竞赛水平。