Array.prototype 的泛型应用April 28, 2010

在开始这篇文章之前,按照“惯例”我们先来道题目(出处)。

题目

请说明下面语句的输出:

x = {shift:[].shift};
x.shift();
console.info(x.length);

如果你回答正确,那么说明你已经了解 Array 函数的泛型应用。在理解这到题目之前,我 我们首先要了解数组(Array)的 shift 定义。

MDC 中已经对相关的说明描述得非常的清楚

shift is intentionally generic; this method can be called or 
applied to objects resembling arrays. Objects which do not 
contain a length property reflecting the last in a series of 
consecutive, zero-based numerical properties may not behave 
in any meaningful manner.

同时,EMCAScript 中的定义也同时定义了对于 shift 操作对于对象 length 属性的改变, 那么基本上我们可以了解到上题中的答案为

0

扩散思维

如果对于上面的题目还无法理解,那么我们更清楚的说明 Array.prototype.shift 对对象 的 length 的影响。

x = {};
Array.prototype.shift.call(x);
console.info(x.length);

很明显,对于对象如果为定义 length 属性,则 shift 则会自动加上 length 属性并设置 为 0

既然已经说到这里,那么下面的题目输出什么留给大家去思考。

x = function (a, b, c) {};
Array.prototype.shift.call(x);
console.info(x.length);

重新认识泛型

很明显,上面的题目有可能还是无法说明本篇文章的题目。泛型(Generic)应用其实 期前也说明过,但这里主要说明 Array 方法对于“类数组”的操作使用。

强制转换为数组

var args = Array.prototype.slice.call(arguments);

这个用法比较火星,其实期前也用过,详细参见这里

迭代数据

Array.prototype.forEach.call(arguments, function(i) {
    console.info(i);
});

如果对象能够被递归,则出了“传统”的 for、while 等语句以外,还可以考虑使用 Array 的 forEach 属性(注意 IE 会是悲剧)。Array 的 forEach 方法详见这里

其他的 Array 扩展用法可以散发自己的思维,如果对应浏览器的 Array 没有对应的实现方 法,可以参见这里

其实,不仅仅是 Array 方法,很多浏览器原生对象的方法都是泛型,我们完全可以利用这 这些特性

  1. 使代码更为的清晰
  2. 使用原生方法,效率更高。

-- EOF --

已有 3 条评论

  1. 在google v8中找到shift方法的源码:
    function ArrayShift() {
    var len = TO_UINT32(this.length);

    if (len === 0) {
    this.length = 0;
    return;
    }

    var first = this[0];

    if (IS_ARRAY(this))
    SmartMove(this, 0, 1, len, 0);
    else
    SimpleMove(this, 0, 1, len, 0);

    this.length = len - 1;

    return first;
    }

    而Function对象的length是参数的个数,这里就是3。这个参数是只读的,所以shift无法改变length的大小,输出为3。

    另,来自MDC:“length is external to a function, and indicates how many arguments the function expects, i.e. the number of formal parameters.“

  2. 长天 长天

    测试了一下下面的例子:

    var a = {}, b = {}, c = {}, d = {};

    Array.prototype.shift.call(a);
    Array.prototype.unshift.call(b);
    Array.prototype.pop.call(c);
    Array.prototype.push.call(d);

    alert("shift: " + a.length + ", unshift: " + b.length + ", pop: " + c.length + ", push: " + d.length);

    测试结果有点意外,出现了3组结果: (IE6与7),(IE8与FF), (chrome, safari, opera)

    ---------------------------
    IE6:
    ---------------------------
    shift: undefined, unshift: undefined, pop: 0, push: undefined

    ---------------------------
    IE7:
    ---------------------------
    shift: undefined, unshift: undefined, pop: 0, push: undefined

    ---------------------------
    IE8
    ---------------------------
    shift: 0, unshift: undefined, pop: 0, push: 0

    ---------------------------
    FF 3.6
    ---------------------------
    shift: 0, unshift: undefined, pop: 0, push: 0

    ---------------------------
    chrome 4:
    ---------------------------
    shift: 0, unshift: 0, pop: 0, push: 0

    ---------------------------
    safari 4:
    ---------------------------
    shift: 0, unshift: 0, pop: 0, push: 0

    ---------------------------
    opera 10:
    ---------------------------
    shift: 0, unshift: 0, pop: 0, push: 0

  3. cc cc

    如1楼说的
    第二个例子不是很好

添加新评论




* Required (but your email address will never be published)

Yahoo 统计