我没有找到关于这个主题的任何信息,请原谅我,如果这是一个非常奇怪的问题。
我知道JS允许将属性定义为访问器,这意味着它们在使用时会触发getter或setter函数。
我的问题是对阵列成员是否可以这样做。
例如,我希望在分配时触发一个setter函数:
myObj[2] = 2 /* set function(value, index) { console.log(value + index) } */
如果无法做到这一点,还有其他方法可以扩展[]操作吗?
答案 0 :(得分:3)
除非你将数组子类化,否则基本上不能。
即使你是子类,数组也比对象更具动态性。与对象不同,它们始终会添加和删除项目,您必须能够动态地将getter和setter连接到每个属性(键)以及添加的项目。不实用。如果一个数组是子类,你可以使用getter和setter修改它的length属性,并尝试从更改到它的length属性来观察数组,但这需要大量的数组差异。
我想使用数组最好使用ES6代理对象。你可以这样做;
function ProxyMaker(a){
return new Proxy(a, { get: function(target, property, receiver) {
console.log(target+"'s "+property+" property has been accessed");
return target[property];
},
set: function(target, property, value, receiver) {
console.log(target+"'s "+property+" property has been modified");
return target[property] = value;
},
has: function(target, property) {
console.log(target+"'s "+property+" property has been checked");
return Reflect.has(target, property); // 10x to @Bergi
}
});
}
var p = ProxyMaker([]);
p[0] = 1;
p[0];
p.push(10);
p.unshift(7);
console.log(JSON.stringify(p))
答案 1 :(得分:1)
如果关键知道值何时发生了变化,则需要创建显式的setter和getter。
如上所述,代理是一个很好的选择。但它可能并非在所有浏览器中都可用。在这种情况下,您可以创建一个新对象,在设置时通知您。
这种方法有很多权衡,实现本机提供的所有数组都是相当多的工作。下面的示例非常简单,但它确实提供了类似交互的数组和一个可以监听的setter事件。
var observableArray = function(eventName) {
var myArray = [];
var api = {};
api.get = function(index) {
if (myArray.length && typeof index === 'number') {
return myArray[index];
}
};
api.set = function(item, index) {
if (typeof index === 'number') {
myArray[index] = item;
}
else {
index = myArray.push(item) - 1;
}
var event = new CustomEvent(eventName, {detail: index});
document.dispatchEvent(event);
return index;
};
api.getLength = function() {
return myArray.length;
};
api.empty = function() {
myArray.splice(0, myArray.length);
};
return api;
};
var arrayListener = document.addEventListener('foo', function(e) {console.log('The index modified: ',e.detail);},false);
var test = new observableArray('foo');
test.set('bar');
console.log('The # of items: ', test.getLength());
test.empty();
console.log('The # of items after empty: ', test.getLength());
如果您只需要一种方法,可以在设置数组值时发生某些事情,则可以扩展数组以使用set方法触发回调。程序员可以使用它。
Array.prototype.set = function(item, index, callback) {
if (typeof index === 'number') {
this[index] = item;
}
else {
index = this.push(item) - 1;
}
if (callback) {
callback.apply(this, [index]);
}
return index;
};
var test2 = [];
test2.set('foo', 4, function(i) {
console.log('Callback value: ', i);
console.log('The array: ', this);
});
答案 2 :(得分:0)
您可以做的是将对象包裹在ES6 proxy。
中var a = new Proxy({}, {get:function(target, name){return 42;}});
console.log(a[0]); // ==> 42
然后您可以捕获并添加处理到get
/ set
操作。
答案 3 :(得分:0)
您有两种访问数组的方法:
被视为具有命名setter / getter的对象var x = pojoArray ['firstName'];
通过数字索引var x = pojoArray [10];
所以你有两种方法可以解决这个问题:
糟糕的方式: 如果将数组视为对象,则可以手动循环整个数组,但在使用像对象这样的数组时应该避免这种情况,因为无法保证顺序。请看以下帖子: Loop through an array in JavaScript
其他选项: 根据您的要求,另一种方法是通过数字索引访问它。您可以创建某种辅助函数,这些函数必须使用数组中正确的索引映射getter和setter键,并确保该键仅使用一次。
请注意,我没有说明'好方法'来满足您的要求。如果可能的话,我会尽量避免使用这些工作流程,因为它们容易出错并导致头痛。