在下面的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有关。
答案 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