这是我以前使用过的结构的准系统,我只在最新的浏览器上对此进行了测试——但是它没有使用任何会导致问题的技术。唯一可能的争用是使用 Array 对对象进行原型设计。但我不明白为什么这在旧浏览器中不起作用:
<script>
"use strict";
var ArrayLike = (function(){
/// create a static reference to our constructor so that we can
/// add methods to ArrayLike... if we like.
var _static = function(){
/// store some "private" values, and arrayify our arguments
var _args = Array.prototype.slice.call( arguments ),
_private = { byKey:{}, byIndex:{} },
_public = this;
/// make sure the user used the 'new' keyword.
if ( _public instanceof _static ) {
/// if we have arguments then push them onto ourselves
if ( _args.length ) {
_public.splice.apply(_public,[0,0].concat(_args));
}
/// Now that a new instance has been created, switch in an array
/// prototype ready for the next instance.
_static.prototype = new Array();
/// start adding our methods, bare in mind if you wish to
/// stop any of the native array methods from working you'll
/// have to override them here.
_public.add = function( key, value ){
/// store the keys and indexes as references to themselves.
_private.byKey[key] = _public.length;
_private.byIndex[_public.length] = key;
/// use the inherited push function from the array.
_public.push( value );
}
/// an example function to show how get by key would work.
_public.getByKey = function(key){
if ( (key = _private.byKey[key]) || key === 0 ) {
return _public[key] ? _public[key] : null;
}
}
/// easy removeAll thanks to the array prototype.
_public.removeAll = function(){
_public.length = 0;
}
/// here I leave you to flesh out the methods that you 'want'.
_public.removeByKey = function(){
}
/// I'll give you a clue that keeping your array index in order
/// is going to be a manual process, so whenever you delete you
/// will have to reindex.
_private.reIndex = function(){
}
}
}
/// set-up the prototype as an array ready for creation
_static.prototype = new Array();
/// return the function that will be our constructor
return _static;
})();
</script>
从普通构造函数的角度来看,上述内容有点奇怪,因为它不断修改其原型,这意味着以下内容无法按预期工作:
var a = new ArrayLike(1,2,3);
alert( a instanceof ArrayLike ); /// alerts FALSE
从数组扩展的好处是非常明显的,因为您现在可以a
像对待任何数组一样对待 - 所以您的一些工作是由核心 JS 代码为您完成的。但是,当您正在实现一个使用键的系统时,最好覆盖大多数正常的数组操作,以便您可以正确跟踪结构中正在使用的键。
无论如何希望它有所帮助,我已经让您解决重新索引数组的稍微棘手的元素,因为它应该与上述设置方式直接相关。
其他增强功能
关于将某些属性设置为只读,这只有在 JavaScript 1.8+ 中才能真正实现——因此它不会向后兼容旧版浏览器。Object.defineProperty(obj, prop, descriptor)
您可以使用Felix Kling 的评论中提到的方法来实现这一点。使用它应该可以影响诸如.length
并使它们只读之类的东西。但是,您对代码的锁定越多,它的灵活性和可扩展性就越差。