为什么在Array的子​​类中设置位置不会改变其长度?我不应该子类化数组吗?

时间:2011-09-16 21:00:29

标签: javascript arrays coffeescript

在下面的CoffeeScript程序中,我创建了一个Array的子类,它在其构造函数中设置了两个位置:

class SetPositionsArray extends Array
  constructor: (x,y) ->
    @[0] = x
    @[1] = y

  myLength: ->
    @length

sp_array = new SetPositionsArray 1, 2

console.log "sp_array: "
console.log sp_array
console.log "sp_array[0]: "
console.log sp_array[0]
console.log "sp_array[1]: "
console.log sp_array[1]
console.log "sp_array.length: "
console.log sp_array.length
console.log "sp_array.myLength(): "
console.log sp_array.myLength()

我希望此代码会更改length的{​​{1}}属性,因为它有效地设置了它的位置。但是,我得到的输出是:

sp_array

即长度为0。

然后,我创建了另一个类,它在实例中推送值而不是设置它们:

$ coffee sp.coffee
sp_array: 
[ 1, 2 ]
sp_array[0]: 
1
sp_array[1]: 
2
sp_array.length: 
0
sp_array.myLength(): 
0

在这种情况下,我得到了预期的结果,除了数组中有实际的 class PushValuesArray extends Array constructor: (x,y) -> @push x @push y myLength: -> @length pv_array = new PushValuesArray 1, 2 console.log "pv_array: " console.log pv_array console.log "pv_array[0]: " console.log pv_array[0] console.log "pv_array[1]: " console.log pv_array[1] console.log "pv_array.length: " console.log pv_array.length console.log "pv_array.myLength(): " console.log pv_array.myLength() 属性(我想这会是一些内部细节):< / p>

length

那么,为什么在数组中设置位置不会改变它的长度?

此问题与我this one发布的this answer有关。

4 个答案:

答案 0 :(得分:8)

最简单的解释是:length是神奇的。

length显然不像普通属性,因为它在其对象上插入/删除其他属性时会更改其值(相反,设置length = 0将删除其他属性);但标识符“长度”并没有什么特别之处。这意味着你可以轻松地写出foo.length = 'bar',世界将继续转向。只有阵列才有它的特殊性。

现在,您可能期望在extend Array class PushValuesArray extends Array (new PushValuesArray) instanceof Array # true 构造函数时,您得到一个数组 - 但是你呢?嗯,从某种意义上说,你做了:

length

不幸的是,出于extends的目的,你没有。这里所有的length关键字都是创建一个原型链,而Array prototype 具有一个非常神奇的Array::length # 0 属性:

PushValuesArray

这就是你在length个实例上得到的全部内容。可悲的是,没有办法在你自己的物体上复制size()魔法。你唯一的选择是编写一个函数(比如Array),或者用你想要的方法修改Array原型,而不是使用真正的数组。

总结一下:子类化$('body').length # 1 $('body')[0] # [object HTMLBodyElement] 不会让你走得太远。这就是为什么,例如,jQuery在其对象上有一个非常类似数组的API -

$('body') instanceof Array  # false

- 但实际上并没有使这些对象继承自Array原型:

{{1}}

答案 1 :(得分:3)

Array.length是doesn't work when subclassed

的特殊属性

如果您查看第一个示例的已编译的javascript,CoffeeScript构建类的方法是创建一个函数并调用__extends(SetPositionsArray, Array);。此方法无法将长度概念“复制”到新类中。

答案 2 :(得分:0)

以下使用node.js并在coffeescript中实现的Array子类,使用util.inherits&amp; Object.defineProperty

util = require 'util'

class NGArray extends []
  constructor : ->

  util.inherits @, Array

  Object.defineProperty NGArray.prototype, "length",
    get: ->
      i = 0 
      for k,v of @
        i++ unless isNaN parseInt(k) 
      i

array = new NGArray()
array[0] = 'value'
array[1] = true
array[2] = ->
array[3] = 568
array.push(false)
array.pop()

console.log(array.length) #4

答案 3 :(得分:0)

我意识到我在游戏中已经很晚了,但你不应该做你正在做的事情。这是我一直在修补的一个例子,我认为没有理由不适合你。

class ArrayWrapper
  constructor: (name, args...)
    @name = name
    @push.apply(@, args)

一旦到位,我可以这样做:

>>> relation = new Relation('foo',1,2,3,4,5)
Object[1, 2, 3, 4, 5]
>>> relation.length
5