Pull to refresh

Нестандартное использование Get и Set в Javascript

Abnormal programming *
Многие в курсе, что в Javascript есть так называемые Getter'ы и Setter'ы. Это конструкции для отслеживания изменения значений свойств объекта, а так же возвращения этих значений. «С изнанки» объекта они выглядят как обычные функции:

var obj = {
   get value() {
     return 0;
   },
   set value(s) {
     alert ("Go screw yourself!")
   }
}


* This source code was highlighted with Source Code Highlighter.


Но раз это функции, их можно использовать как душе угодно!



Например, мы можем сделать конструктор, который упростит нашу работу с CSS некоего HTML элемента:
function $(object) {
if(typeof(object)=="string"){object=document.getElementById(object)};
object.__defineGetter__("x",function(){
return (parseInt(object.style.left))
}),
object.__defineSetter__("x",function(n){
object.style.left = n + 'px'
}),
object.__defineGetter__("y",function(){
return (parseInt(object.style.left))
}),
object.__defineSetter__("y",function(n){
object.style.top = n + 'px'
})
}


* This source code was highlighted with Source Code Highlighter.


Теперь к кнопку с id «btn1» можно переместить, написав $("btn1").x = 56.

Но прелесть Getter'ов и Setter'ов не только в упрощении повседневных задач, типа работы с CSS. Их можно использовать даже для изменения концепции самого языка:

Например, следующий пример выведет сообщение на экран:

obj = {
  set message(s) {
  alert(s)
  }
}

obj.message = "Hello, World!"


* This source code was highlighted with Source Code Highlighter.


Страшно? По-моему, очень. Главное в этом деле не дойти до абсурда. Есть этому и математическое применение:

Например, у нас есть объект Obj, у которого есть свойство value, а также свойство sin. Обращаясь к свойству sin, мы получаем синус от value. Соль в том, что с помощью Setter'а можно сделать наоборот. Тогда после изменения sin, изменится и value. Одним словом, если sin==0.5, то value=Math.PI/6.

obj = {
 value: 0,
  get sin() {
  return Math.sin(this.value)
  }
  set sin(n) {
  this.value = Math.asin(n)
  }
}


* This source code was highlighted with Source Code Highlighter.


Стоит отметить, что решение не вполне кроссбраузерное. Если хотите портировать все это на ваш любимый Internet Explorer браузер, вам следует использовать __defineGetter__() и __defineSetter__(), либо методы, описанные здесь, и, в крайнем случае, здесь.

Но возможностей у Getter'ов и Setter'ов действительно много. Если скомбинировать все с тем же AJAX, можно добиться вполне кошерного вида вроде:

ajax.url = "script.php"
alert(ajax.result)


* This source code was highlighted with Source Code Highlighter.


Это, конечно, введет в замешательство некоторых программистов, привыкших к тому, что операция присваивания не делает ничего, кроме присваивания (собственно, как и операция взятия значения). Одно но, придется что-то сделать с методами без параметров, типа .Destroy(), ибо писать Obj.Destroy = true уж точно никто не будет. Есть идея сделать что-то вроде тайм-аута по тикам, т.е. отслеживать каждый get и set. Это значит, что Obj.Destroy = 5 уничтожит объект через 5 get/set операций. Но это, понятное дело, уже излишний креатив.
Tags:
Hubs:
Total votes 67: ↑50 and ↓17 +33
Views 4.6K
Comments Comments 24