繁体   English   中英

的JavaScript。 创建类似数组的对象。 可以使.length自动递增吗?

[英]Javascript. Creating Array-like objects. Is it possible to make .length autoincrement?

关于创建和继承类似Array的对象的事情太多了,但是我的问题之一仍未得到解答:是否有可能以某种方式向对象添加自动递增的.length属性?
示例脚本:

function ArrayLike(){
    this.length=0;
    this.splice=[].splice;
}
var Arr=new ArrayLike();
Arr[0]=0;
Arr[1]=1;
alert(Arr.length); //alerts "0" instead of "2"

当然,我可以添加一些方法,例如:

function ArrayLike(){
    this.length=0;
    this.splice=[].splice;
    this.push=function(toadd){
        this[this.length++]=toadd;
    }
}

但这不是我要尝试做的。

因此,当我以Arr[N]='blah-blah-blah'的方式向对象添加内容时,是否可以增加.length?

是否有可能以某种方式添加autoincrement .length属性

并不是的; 至少,您不能围绕length和索引属性执行Array所有操作。

在启用ES5的环境中,可以使用getter和setter函数将length为属性。 但是找出length应该是很尴尬的,因为到目前为止,还没有“全部捕获”的设置方法,例如:

arr[1] = "foo";

...运行。 (ES6很有可能通过代理具有所有属性设置器。)

因此,您的length必须从对象内容中找出来,这不是很有效,例如:

var explicitLength;
Object.defineProperty(this, "length", {
    get: function() {
        var length;

        // Find our length from our max index property
        length = Object.keys(this).reduce(function(maxIndex, key) {
            var index = key === "" ? NaN : +key;
            if (!isNaN(index) && index > maxIndex) {
                return index;
            }
            return maxIndex;
        }, -1) + 1;

        // If we have an explicitly-set length, and it's greater,
        // use that instead. Note that if explicitLength is
        // `undefined`, the condition will always be false.
        if (explicitLength > length) {
            length = explicitLength;
        }

        return length;
    },
    set: function(value) {
        explicitLength = value;
        // You might choose to have code here removing properties
        // defining indexes >= value, likes Array does
    }
});

请注意,即使我们有一个明确设置的长度,我们仍然必须检查自然长度是否更大,以处理:

arr.length = 2;
arr[5] = "foo";
console.log(arr.length); // Should be 6, not 2

在属性检索上做很多工作显然不是一件好事,所以我会避免这种事情。


在上面我说: “所以我会避免这种事情。”

好吧,这一切都很好,但是您应该怎么做呢?

假设你有功能的niftyspiffy ,你想拥有可用。 您有两个现实的选择:

  1. 使用实际的数组,然后将自定义方法混入每个数组实例

  2. 增强Array.prototype

#1使用实际的数组并混合使用方法

您可以在一个方便的对象上定义方法,例如ArrayMixin

var ArrayMixin = {
    nifty: function() {
        // ...do something nifty with `this`
    },
    spiffy: function() {
        // ...do something spiffy with `this`
    }
};

然后具有用于创建数组的构建器功能:

function createArray(arr) {
    arr = arr || []; // `arr` is optional
    extend(arr, ArrayMixin);
    return arr;
}

您问这个extend功能是什么? 将属性从一个对象复制到另一个对象的东西。 如果您使用任何库或框架(jQuery,Underscore,Angular,PrototypeJS等),它们可能都具有某种实现此目的的extend功能。 他们通常会是这个样子(这是很现成的,袖口)。

function extend(target) {
    var arg, obj, key;
    for (arg = 1; arg < arguments.length; ++arg) {
        obj = arguments[arg];
        for (key in obj) {
            if (obj.hasOwnProperty(key)) {
                target[key] = obj[key];
            }
        }
    }
    return target;
}

请注意,这是一个浅表副本,它不会试图使它添加到target的属性不可枚举。 根据需要进行调整。

因此,当您想要一个数组时:

var a = createArray(['one', 'two', 'three']);

...和a具有niftyspiffy就可以了。

例:

 var ArrayMixin = { nifty: function() { this.forEach(function(entry, index) { this[index] = entry.toUpperCase(); }, this); return this; }, spiffy: function() { this.forEach(function(entry, index) { this[index] = entry.toLowerCase(); }, this); return this; } }; function createArray(arr) { arr = arr || []; // `arr` is optional extend(arr, ArrayMixin); return arr; } function extend(target) { var arg, obj, key; for (arg = 1; arg < arguments.length; ++arg) { obj = arguments[arg]; for (key in obj) { if (obj.hasOwnProperty(key)) { target[key] = obj[key]; } } } return target; } var a = createArray(['one', 'two', 'three']); a.nifty(); snippet.log(a.join(", ")); a.spiffy(); snippet.log(a.join(", ")); 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

增强Array.prototype

人们对增强Array.prototype ,但实际上并没有错。 造成麻烦的唯一原因是,如果人们使用的破损代码希望for-in数组索引中循环那么您必须增强原型,而又不能使新方法不可枚举。 但同样,该代码已损坏; for-in 不是用于遍历数组索引,而是用于遍历对象属性。

所以这里是增强Array.prototype

(function(aproto) {
    var add;
    if (Object.defineProperty) {
        // Function to add a non-enumerable property
        add = function(obj, prop, value) {
            Object.definePrperty(obj, prop, {
                value: value
            });
        };
    } else {
        // Old JavaScript engine, oh well
        add = function(obj, prop, value) {
            obj[prop] = value;
        };
    }

    add(aproto, "nifty", function() {
        // ...do something nifty with `this`
    });

    add(aproto, "spiffy", function() {
        // ...do something spiffy with `this`
    });

})(Array.prototype);

现在,使用它确实很干净:

var a = ['one', 'two', 'three'];

...和a具有niftyspiffy就可以了。

例:

 (function(aproto) { var add; if (Object.defineProperty) { // Function to add a non-enumerable property add = function(obj, prop, value) { Object.defineProperty(obj, prop, { value: value }); }; } else { // Old JavaScript engine, oh well add = function(obj, prop, value) { obj[prop] = value; }; } add(aproto, "nifty", function() { this.forEach(function(entry, index) { this[index] = entry.toUpperCase(); }, this); }); add(aproto, "spiffy", function() { this.forEach(function(entry, index) { this[index] = entry.toLowerCase(); }, this); }); })(Array.prototype); var a = ['one', 'two', 'three']; a.nifty(); snippet.log(a.join(", ")); a.spiffy(); snippet.log(a.join(", ")); 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM