2016-10-13 36 views
3

我还没有找到关于这个话题的任何信息,所以请原谅我,如果这是一个非常奇怪的问题。JS:是否可以在阵列成员上定义getter函数?

我知道JS允许将属性定义为访问器,意味着它们在使用时触发getter或setter函数。

我的问题是,是否可以对阵列成员做同样的事情。

例如,我要一个setter函数火分配这样的时候:

myObj[2] = 2 /* set function(value, index) { console.log(value + index) } */ 

如果这是不可能的,还有没有其他的方法可以延长[]操作?

+1

你的意思只是对于属性“'2'”还是对所有索引? – Bergi

+0

@Bergi所有指数 – user1533299

+0

然后你想要一个代理,是的。另请参见[here](http://stackoverflow.com/a/11523671/1048572) – Bergi

回答

1

基本上除非你为一个数组创建子类,否则你不能。

即使您是子类,数组也比对象更具动态性。与对象不同,它们会一直添加和删除项目,并且必须能够将getter和setter动态附加到每个属性(键)以及添加的项目。不实际。如果一个数组是分类的,你可以使用getter和setter修改它的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))

+0

您的'拥有'陷阱不适用于falsy值。 – Bergi

+0

@Bergi是:)什么是正确的方式与反思..? – Redu

+1

可能'Reflect.has(target,property)',afaik它们被设计成与陷阱具有完全相同的签名,因此即使没有记忆细节也很容易 – Bergi

0

你可以做的是将对象包装在ES6 proxy中。

var a = new Proxy({}, {get:function(target, name){return 42;}}); 

console.log(a[0]); // ==> 42 

那么你可以捕获并添加处理get/set操作。

0

你必须访问阵列的方法有两种:

  1. 视为带有一个名为设定器/吸气VAR X = pojoArray [ '的firstName']的对象;

  2. 通过数字索引var x = pojoArray [10];

所以,你必须处理这个两种方式,因为我看到它:

糟糕的方式: 如果你把数组类似于对象,你可以循环整个数组手动但应该是避免使用像对象这样的数组,因为顺序不能保证。请参阅以下职位: Loop through an array in JavaScript

其他选项: 按照您的要求,其他的方式做,这是通过数字索引来访问它。你可以创建一些辅助函数,这些辅助函数必须将getter和setter键映射到数组中适当的索引,并确保该键只使用一次。

请注意,我没有声明'好方法'满足您的要求。如果可能的话,我会尽量避免这些工作流程中的任何一个,因为这些工作流程很容易出错并导致头痛。

1

如果关键是要知道值何时发生了变化,您需要创建显式设置器和获取器。

正如所建议的,如果可用,Proxy是一个不错的选择。它可能不适用于所有浏览器。在这种情况下,您可以创建一个新对象,在设置时通知您。

这种方法存在很多折衷,而且实现数组本身提供的所有东西都是相当多的工作。下面的例子非常简单,但它确实提供了数组,如交互和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()); 

如果你只需要一种能够使当阵列值设置事情发生,你可以扩展阵列有一个触发回调一套方法。这取决于程序员使用它。

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); 
}); 
+0

我不知道哪一个给答案标签......你的答案不使用ES6,但同时它不扩展''[/ * Number * /]'运算符,就像访问者扩展'='运算符一样。 – user1533299

相关问题