吸气/器javascript阵?
-
20-09-2019 - |
题
有没有办法得到一个get/set行为的一系列?我想事情是这样的:
var arr = ['one', 'two', 'three'];
var _arr = new Array();
for (var i = 0; i < arr.length; i++) {
arr[i].__defineGetter__('value',
function (index) {
//Do something
return _arr[index];
});
arr[i].__defineSetter__('value',
function (index, val) {
//Do something
_arr[index] = val;
});
}
解决方案
数组访问是正常属性访问没有什么不同。 array[0]
装置array['0']
,这样就可以通过定义与名称'0'
和截距访问第一数组项的属性。
然而,这并使它不切实际的所有,但短,更多或更少的固定长度的阵列。你不能对所有一气呵成“碰巧是整数所有名称”定义的属性。
其他提示
使用代理,你可以得到所需的行为:
var _arr = ['one', 'two', 'three'];
var accessCount = 0;
function doSomething() {
accessCount++;
}
var arr = new Proxy(_arr, {
get: function(target, name) {
doSomething();
return target[name];
}
});
function print(value) {
document.querySelector('pre').textContent += value + '\n';
}
print(accessCount); // 0
print(arr[0]); // 'one'
print(arr[1]); // 'two'
print(accessCount); // 2
print(arr.length); // 3
print(accessCount); // 3
print(arr.constructor); // 'function Array() { [native code] }'
<pre></pre>
在代理构造函数将创建一个对象包装称为陷阱重写基本行为我们的阵列和使用函数。该get
功能将被调用的任何属性查找,和doSomething()
返回值之前。
代理是一个ES6特征和IE11或更低不被支持。请参阅浏览器兼容性列表
我在约翰Resig的文章的JavaScript getter和setter 的抬头,但他的原型例如没有为我工作。尝试一些替代品后,我发现一个似乎工作。您可以通过以下方式使用Array.prototype.__defineGetter__
:
Array.prototype.__defineGetter__("sum", function sum(){
var r = 0, a = this, i = a.length - 1;
do {
r += a[i];
i -= 1;
} while (i >= 0);
return r;
});
var asdf = [1, 2, 3, 4];
asdf.sum; //returns 10
为我工作在铬和Firefox。
我希望它能帮助。
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0; i < this.length; i++)
iterator(this[i]);
},
clear: function() {
this.length = 0;
return this;
},
first: function() {
return this[0];
},
last: function() {
return this[this.length - 1];
},
compact: function() {
return this.select(function(value) {
return value != undefined || value != null;
}
);
},
flatten: function() {
return this.inject([], function(array, value) {
return array.concat(value.constructor == Array ?
value.flatten() : [value]);
}
);
},
without: function() {
var values = $A(arguments);
return this.select(function(value) {
return !values.include(value);
}
);
},
indexOf: function(object) {
for (var i = 0; i < this.length; i++)
if (this[i] == object) return i;
return -1;
},
reverse: function(inline) {
return (inline !== false ? this : this.toArray())._reverse();
},
shift: function() {
var result = this[0];
for (var i = 0; i < this.length - 1; i++)
this[i] = this[i + 1];
this.length--;
return result;
},
inspect: function() {
return '[' + this.map(Object.inspect).join(', ') + ']';
}
}
);
可以为 JavaScript 数组定义 Getters 和 Setters。但你不能同时拥有访问器和值。参见 Mozilla 文档:
不可能同时将 getter 绑定到某个属性并让该属性实际保存一个值
因此,如果您为数组定义访问器,则需要有第二个数组来存储实际值。下列 例子 说明了这一点。
//
// Poor man's prepare for querySelector.
//
// Example:
// var query = prepare ('#modeler table[data-id=?] tr[data-id=?]');
// query[0] = entity;
// query[1] = attribute;
// var src = document.querySelector(query);
//
var prepare;
{
let r = /^([^?]+)\?(.+)$/; // Regular expression to split the query
prepare = function (query, base)
{
if (!base) base = document;
var q = []; // List of query fragments
var qi = 0; // Query fragment index
var v = []; // List of values
var vi = 0; // Value index
var a = []; // Array containing setters and getters
var m; // Regular expression match
while (query) {
m = r.exec (query);
if (m && m[2]) {
q[qi++] = m[1];
query = m[2];
(function (qi, vi) {
Object.defineProperty (a, vi, {
get: function() { return v[vi]; },
set: function(val) { v[vi] = val; q[qi] = JSON.stringify(val); }});
})(qi++, vi++);
} else {
q[qi++] = query;
query = null;
}
}
a.toString = function () { return q.join(''); }
return a;
}
}
该代码使用三个数组:
- 一个为实际值,
- 一个用于 JSON 编码值
- 一个用于访问器。
带有访问器的数组将返回给调用者。当一个 set
通过将值分配给数组元素来调用,包含纯值和编码值的数组将被更新。什么时候 get
被调用时,它仅返回普通值。和 toString
返回包含编码值的整个查询。
但正如其他人已经说过的:仅当数组的大小恒定时,这才有意义。您可以修改数组的现有元素,但不能添加其他元素。
为什么不用于内的对象创建一个新类?
var a = new Car();
function Car()
{
// here create the setters or getters necessary
}
然后,
arr = new Array[a, new Car()]
我觉得你的想法。
它可以创建者以为每一个元件阵列,但是有一个限制:你就不能直接设置阵元的索引外的初始化的区域(例如 myArray[2] = ... // wouldn't work if myArray.length < 2
)使用的阵列。原型功能将工作。(例如推,爸爸,接头,转移,回.) 我举一个例子如何完成这个 在这里,.
您可以添加任何你喜欢的方法来一个Array
,加入他们Array.prototype
。下面是增加了一个吸气剂和示例设置器
Array.prototype.get = function(index) {
return this[index];
}
Array.prototype.set = function(index, value) {
this[index] = value;
}
这是我做事的方式。你将不得不调整原型创作(我删除从我的版本有点)。但是,这会给你我在其他基于类的语言中使用的默认的getter / setter行为。 定义getter和没有setter意味着写入元件将被忽略...
希望这有助于。
function Game () {
var that = this;
this._levels = [[1,2,3],[2,3,4],[4,5,6]];
var self = {
levels: [],
get levels () {
return that._levels;
},
setLevels: function(what) {
that._levels = what;
// do stuff here with
// that._levels
}
};
Object.freeze(self.levels);
return self;
}
这给了我的预期行为:
var g = new Game()
g.levels
/// --> [[1,2,3],[2,3,4],[4,5,6]]
g.levels[0]
/// --> [1,2,3]
这dmvaldman占用critizism:书写现在应是不可能的。 我改写的代码为1)不使用depracated元件(__ defineGetter __)和2)不接受任何书面(即:不受控制的写入)到水平元件。一个例子设定器是包括在内。 (我不得不添加间隔至__因为降价的defineGetter)
从dmvaldmans请求:
g.levels[0] = [2,3,4];
g.levels;
/// --> [[1,2,3],[2,3,4],[4,5,6]]
//using setter
g.setLevels([g.levels, g.levels, 1,2,3,[9]]);
g.levels;
/// --> [[[1,2,3],[2,3,4],[4,5,6]],[[1,2,3],[2,3,4],[4,5,6]], ....]
//using setLevels
g.setLevels([2,3,4]);
g.levels;
/// --> [2,3,4]
此答案仅仅是一个延伸到基于代理的溶液。 请参阅使用代理的解决方案,在提到,只得到,但我们也可以使用 设置为我显示在这里。
注意:在组第三参数可以携带值...
代码是自解释的。
var _arr = ['one', 'two', 'three'];
var accessCount = 0;
function doSomething() {
accessCount++;
}
var arr = new Proxy(_arr, {
get: function(target, name) {
doSomething();
return target[name];
},
set: function(target, name, val) { doSomething(); target[name] = val; }
});
function print(value) {
document.querySelector('pre').textContent += value + '\n';
}
print(accessCount); // 0
print(arr[0]); // 'one'
print(accessCount); // 1
arr[1] = 10;
print(accessCount); // 2
print(arr[1]); // 10