문제

배열에서 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 이하로 지원되지 않습니다. 보다 브라우저 호환성 목록.

나는 John Resig의 기사를 찾았습니다 JavaScript getters and 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

Chrome과 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 및 Setter를 정의 할 수 있습니다. 그러나 동시에 접근자와 가치를 가질 수 없습니다. 모질라를 참조하십시오 선적 서류 비치:

동시에 재산에 묶인 게터가 있고 그 속성이 실제로 가치를 유지할 수는 없습니다.

따라서 배열에 대한 액세서를 정의하면 실제 값에 대한 두 번째 배열이 있어야합니다. 다음과 같은 예시 그것을 설명합니다.

//
// 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;
  }
}

코드는 세 가지 배열을 사용합니다.

  1. 실제 값을위한 하나,
  2. JSON 인코딩 된 값을위한 것입니다
  3. 그리고 접근자를위한 하나.

액세서가있는 배열은 발신자에게 반환됩니다. A. 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) 배열을 사용하여 프로토 타입 함수가 작동합니다. (예 : Push, Pop, Splice, Shift, Unshift.) 나는 이것을 달성하는 방법의 예를 제시합니다. 여기.

원하는 방법을 추가 할 수 있습니다 Array, 그것들을 추가함으로써 Array.prototype. 다음은 getter and setter를 추가하는 예입니다.

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의 비평을 취하는 것은 이제 글쓰기가 불가능합니다. 나는 코드를 1) 타락한 요소 (__ 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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top