如何创建其行为像一个真正的数组构造? [英] How to create a constructor which behaves like a true Array?
问题描述
如何创建一个自定义的数组构造,这是原生Array构造函数的扩展版本?
jQuery的,例如,看起来像其他方法,如 $()数组。addClass
。然而,它并没有修改 Array.prototype
,因为新的Array()。hasClass
是未定义
。
所以,我怎样才能创建一个扩展阵列实现,而无需修改 Array.prototype
?
示例:
员工(...)// - > [{名称:'约翰',年龄:32},{名称:'鲍勃',年龄:29}];
员工(...).byAge(32)// - > [{名称:'约翰',年龄:32}];
//和
。阵列()// byAge - >未定义
jQuery是不是真正的数组实现:<!code>的jQuery的instanceof阵列为假
如果你想创建一个数组的真实情况下,和添加自定义的方法,使用这个code。它采用 Function.prototype.bind
调用构造函数参数的任意数量。
的实施行为的究竟作为一个真正的数组,除了在一个点上:
- 当
阵列
构造函数带一个参数,它的创建与此参数的长度数组。 - 由于此功能往往是错误的根源,我决定忽略它在执行。您仍然可以通过设置
长度
属性设置中的 N 的长度。
code: http://jsfiddle.net/G3DJH/
职能部门的员工(){
//缺少新新政
如果(!(这个的instanceof员工)){
//转换参数数组,因为我们有1至所有索引转移
变参= Array.prototype.slice.call(参数);
args.unshift(本); //移所有索引,设置本
返回新(Function.prototype.bind.apply(雇员,参数));
}其他{
//设置length属性。
VAR LEN =与arguments.length,
/ *
* fn_internalLength:用于计算长度内部方法
** /
fn_internalLength,
/ *
* explicitLength:涉及明确的长度设定
** /
explicitLength = 0; //设置所有的数字键
而(len--){
这个[LEN] =参数[LEN]
} //定义长度内部方法
fn_internalLength =功能(){
VAR allKeys = Object.keys(本)的.sort(函数(X,Y){
//排序列表。顶部最高指标。
返回是 - X;
}),I = -1,长度= allKeys.length,的tmpKey,
foundLength = 0; //循环遍历所有的键
而(+ I&所述;长度&放大器;及(的tmpKey = allKeys [I])&GT; = 0){
//是关键是INTEGER?
如果(的tmpKey - 的tmpKey === 0安培;&放大器;的tmpKey%1 === 0){
foundLength = 1 *的tmpKey + 1;
打破;
}
}
//返回MAX(实际长度,显式地设置长度)
返回foundLength&GT; explicitLength? foundLength:explicitLength;
} .bind(本); //定义魔法length属性
Object.defineProperty(这一点,长度,
{
得到:fn_internalLength,
设置:功能(满足newLength){
VAR长度= fn_internalLength();
如果(满足newLength&LT;长度){
对于(VAR I =满足newLength; I&LT;长度;我++){
删除[I]
}
}
//设置明确的长度
explicitLength =满足newLength;
},
枚举:假的,
配置:假的
});
}
}
Employees.prototype =新的阵列;
//例:自定义的方法:
Employees.prototype.print =功能(){
返回this.join(' - '); //使用继承Array.prototype.join
};//就像阵列,`new`是可选
的console.log(新员工(1,2).PRINT());
的console.log(雇员(1,2).PRINT());//是对象的数组?
的console.log(新员工()的instanceof阵列); //真!
//不能相信吗?
的console.log(新员工()的instanceof员工); //真!
How can I create a custom array constructor, which is an extended version of the native Array constructor?
jQuery, for example, looks like an array with additional methods, such as $().addClass
. However, it didn't modify Array.prototype
, because new Array().hasClass
is undefined
.
So, how can I create an extended array implementation, without modifying Array.prototype
?
Example:
Employees( ... ) //-> [{name: 'John', age: 32}, {name: 'Bob', age: 29}];
Employees( ... ).byAge(32)//-> [{name: 'John', age: 32}];
// and
Array().byAge //-> undefined
jQuery is not a true Array implementation: jQuery instanceof Array
is false!
If you want to create a true instance of an array, and add custom methods, use this code. It uses Function.prototype.bind
to call a constructor with an arbitrary number of parameters.
The implementation behaves exactly as a true array, except at one point:
- When the
Array
constructor is called with a single argument, it's creating an array with a length of this argument. - Since this feature is often a source of bugs, I have decided to omit it in the implementation. You can still set a length of n by setting the
length
property.
Code: http://jsfiddle.net/G3DJH/
function Employees() {
// Deal with missing "new"
if (!(this instanceof Employees)) {
// Convert arguments to an array, because we have to shift all index by 1
var args = Array.prototype.slice.call(arguments);
args.unshift(this); // Shift all indexes, set "this"
return new (Function.prototype.bind.apply(Employees, args));
} else {
// Set length property.
var len = arguments.length,
/*
* fn_internalLength: Internal method for calculating the length
**/
fn_internalLength,
/*
* explicitLength: Deals with explicit length setter
**/
explicitLength = 0;
// Setting all numeric keys
while (len--) {
this[len] = arguments[len];
}
// Internal method for defining lengths
fn_internalLength = function() {
var allKeys = Object.keys(this).sort(function(x, y) {
// Sort list. Highest index on top.
return y - x;
}), i=-1, length = allKeys.length, tmpKey,
foundLength = 0;
// Loop through all keys
while (++i < length && (tmpKey = allKeys[i]) >= 0) {
// Is the key is an INTEGER?
if (tmpKey - tmpKey === 0 && tmpKey % 1 === 0) {
foundLength = 1*tmpKey + 1;
break;
}
}
// Return MAX(actual length, explictly set length)
return foundLength > explicitLength ? foundLength : explicitLength;
}.bind(this);
// Define the magic length property
Object.defineProperty(this, 'length',
{
get: fn_internalLength,
set: function(newLength) {
var length = fn_internalLength();
if (newLength < length) {
for (var i=newLength; i<length; i++) {
delete this[i];
}
}
// Set explicit length
explicitLength = newLength;
},
enumerable: false,
configurable: false
});
}
}
Employees.prototype = new Array;
// Example: Custom method:
Employees.prototype.print = function() {
return this.join('--'); // Using inherit Array.prototype.join
};
// Just like the Array, `new` is optional
console.log(new Employees(1,2).print());
console.log(Employees(1,2).print());
// Is the object an array?
console.log(new Employees() instanceof Array); // True!
// Can't believe it?
console.log(new Employees() instanceof Employees); // True!
这篇关于如何创建其行为像一个真正的数组构造?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!