Есть несколько предыдущих вопросов о том, как StackOverflow задает вопрос о доступе к локальным переменным через цепочку областей видимости, например, если вы хотите ссылаться на локальные переменные, используя нотацию в виде скобок и строку, вам нужно что-то вроде __local__["varName"]
. До сих пор я не нашел даже самого хакерского метода для достижения этого и не придумал метод после нескольких часов использования каждого трюка, который я знаю.
Цель состоит в том, чтобы реализовать геттеры/сеттеры на произвольных неравномерных переменных. Object.defineProperties или __defineGet/Setter__
требуют вызова контекста. Для свойств в глобальном или оконном контексте вы можете выполнить задачу установки сеттера/получателя для прямых ссылок на объект.
Object.defineProperty(this, "glob", {get: function(){return "direct access"})
console.log(glob); //"direct access"
Даже в моих тестах с пользовательским расширением я скомпилирован в модифицированный Chromium, который выполняется до создания любого окна, где контекст является фактическим глобальным контекстом, и даже попытка вызвать this
непосредственно в глобальном контексте приводит к сбой моей программы, Я могу снять это без помех:
Object.defineProperty(Object.prototype, "define", {
value: function(name, descriptor){
Object.defineProperty(this, name, descriptor);
}
};
define("REALLYglobal", {get: function(){ return "above window context"; }});
И тогда он доступен во всех фреймах, созданных позже, в качестве глобального маршрутизируемого через указанный getter/setter. Старый __defineGet/Setter__
также работает в этом контексте, не указывая, на что его можно называть (в Firefox он не работает, но метод выше).
Таким образом, в основном можно определить get/set защиты для любой переменной на объекте, включая контекст окна/глобального контекста с прямым вызовом объекта (вам не нужно window.propname
, просто propname
). Это проблема в том, что вы не можете ссылаться на неграмотные скопированные переменные, являясь единственным типом, который может находиться в доступной области, но не имеет адресного контейнера. Конечно, они также наиболее часто используются, так что это не край. Эта проблема также превосходит текущую реализацию Proxies в ES6/Harmony, поскольку проблема связана с тем, что не может обращаться к локальному контейнеру объектов с синтаксисом языка.
Причина, по которой я хочу быть в состоянии сделать это, - это единственный барьер, позволяющий перегрузить большинство математических операторов для использования в сложных объектах, таких как массивы и хэши, и получить сложное итоговое значение. Мне нужно иметь возможность подключаться к сеттеру в случаях, когда значение задается для типа объекта, который я настроил для перегрузки. Нет проблем, если объект может быть глобальным или может содержаться в родительском объекте, что, вероятно, связано с тем, с чем я буду работать. Он по-прежнему полезен с a.myObject
, но цель состоит в том, чтобы сделать его максимально прозрачным.
Не только это, но было бы очень полезно выполнить что-то вроде этого:
var point3d = function(){
var x, y, z;
return {
get: function(){ return [x, y, z]; },
set: function(vals){ x=vals[0]; y=vals[1]; z=vals[2]; }
};
};
(Это похоже на деструктурирование ES6, но имеет более общие приложения для реализации функциональных возможностей, связанных с получением/настройкой, а не только для передачи сложных значений). Даже этот базовый код полностью провалится:
var x = {myname: "intercept valueOf and :set: to overload math ops!", index: 5};
x++; //x is now NaN if you don't implement a setter somehow
Мне все равно, насколько хриплым является решение, на данный момент это просто интенсивное любопытство для меня относительно того, можно ли это сделать, даже если это требует нарушения любой лучшей практики, которая существует. Я разбил Firefox и Chrome несколько сотен раз, преследуя это до сих пор, делая такие вещи, как переопределение/перехват/изменение Object.prototype.valueOf/toString
, Function.prototype
Function.prototype.constructor
, Function.prototype.call/apply
, arguments.callee.caller
и т.д. С бесконечной рекурсией ошибок и еще чего-то в попытках задним числом приспособить условия бурения. Единственное, что я смог сделать, это обернуть в основном все это с помощью eval и динамического построения кусков кода, что является мостом слишком далеко для меня когда-либо на самом деле. Единственным удаленным удаленным маршрутом было использование with
в сочетании с предварительным определением всех локальных переменных в контейнере, но это, очевидно, очень навязчиво над проблемами с использованием with
.