Javascript 为什么在数组的子类中设置位置不改变其长度?我不应该子类数组吗?
在下面的CoffeeScript程序中,我创建了Javascript 为什么在数组的子类中设置位置不改变其长度?我不应该子类数组吗?,javascript,arrays,coffeescript,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
的子类,它在构造函数中设置了两个位置:
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()
我希望此代码能够更改sp_数组
的length
属性,因为它可以有效地设置数组上的位置。但是,我得到的结果是:
$ coffee sp.coffee
sp_array:
[ 1, 2 ]
sp_array[0]:
1
sp_array[1]:
2
sp_array.length:
0
sp_array.myLength():
0
也就是说,长度是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()
在本例中,我得到了预期的结果,除了数组中有一个实际的length
属性(而我可以想象它是一些内部细节):
那么,为什么在数组中设置位置不会更改其长度呢
这个问题与我发布的相关。最简单的解释是:
长度是魔法
length
显然不像普通属性,因为当您在其对象上插入/删除其他属性时,它会更改其值(相反,设置length=0
将删除其他属性);但标识符“长度”并没有什么特别之处。这意味着您可以轻松地编写foo.length='bar'
,世界将继续转动。只有在数组上,它才有其特殊性
现在,当您扩展数组
构造函数时,您可能会期望得到一个数组,但是您呢?从某种意义上说,你是这样做的:
class PushValuesArray extends Array
(new PushValuesArray) instanceof Array # true
不幸的是,对于长度
,您没有。这里所有的extends
关键字都是创建一个原型链,数组原型有一个明显的非魔法length
属性:
Array::length # 0
这就是您在PushValuesArray
实例中得到的全部内容。遗憾的是,无法在您自己的对象上复制长度
魔法。您唯一的选择是编写一个函数(例如,size()
),或者使用所需的方法修改Array
原型,并使用真正的数组
总之:子类化Array
不会让您走得很远。这就是为什么,例如,jQuery在其对象上有一个非常类似于Array的API-
$('body').length # 1
$('body')[0] # [object HTMLBodyElement]
-但实际上并没有使这些对象从阵列原型继承:
$('body') instanceof Array # false
Array.length是一个特殊的属性
如果您在第一个示例中查看已编译的javascript,那么CoffeeScript构建类的方式是创建一个函数并调用\uuu extenses(SetPositionsArray,Array)代码>。此方法无法将长度概念“复制”到新类中。以下数组子类使用node.js并在coffeescript中实现,使用util.inherits&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
我意识到我在这里已经很晚了,但你不应该做你正在做的事情。这是一个我一直在修补的例子,我看不出为什么它不适合你
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
>>> relation = new Relation('foo',1,2,3,4,5)
Object[1, 2, 3, 4, 5]
>>> relation.length
5