2008-11-08 4 views
28

Есть ли способ получить все методы (частные, привилегированные или общедоступные) из объекта javascript изнутри? Вот пример объекта:Javascript Reflection

var Test = function() { 
// private methods 
    function testOne() {} 
    function testTwo() {} 
    function testThree() {} 
// public methods 
    function getMethods() { 
     for (i in this) { 
     alert(i); // shows getMethods, but not private methods 
     } 
    } 
    return { getMethods : getMethods } 
}(); 

// should return ['testOne', 'testTwo', 'testThree', 'getMethods'] 
Test.getMethods(); 

Текущий номер является кодом в getMethods(), упрощенный пример возвратит только открытые методы, но не частные.

Редактировать: мой тестовый код может (или не может) быть чрезмерным, что я надеюсь получить. учитывая следующее:

function myFunction() { 
    var test1 = 1; 
    var test2 = 2; 
    var test3 = 3; 
} 

есть способ, чтобы выяснить, какие существуют переменные в myFunction() внутри myFunction(). псевдокод будет выглядеть так:

function myFunction() { 
    var test1 = 1; 
    var test2 = 2; 
    var test3 = 3; 

    alert(current.properties); // would be nice to get ['test1', 'test2', 'test3'] 
} 

ответ

28

Техническая причина, по которой эти методы скрыты, двояка.

Во-первых, когда вы выполняете метод на тестовом объекте, «это» будет нетипизированным объектом, возвращаемым в конце анонимной функции, которая содержит общедоступные методы на Module Pattern.

Во-вторых, методы testOne, testTwo и testThree не привязаны к определенному объекту и существуют только в контексте анонимной функции. Вы можете прикрепить методы к внутреннему объекту, а затем разоблачить их с помощью общедоступного метода, но это будет не так чисто, как исходный шаблон, и это не поможет, если вы получаете этот код от третьего лица.

Результат будет выглядеть примерно так:

var Test = function() { 
    var private = { 
     testOne : function() {}, 
     testTwo : function() {}, 
     testThree : function() {} 
    }; 

    function getMethods() { 
     for (i in this) { 
      alert(i); // shows getMethods, but not private methods 
     } 
     for (i in private) { 
      alert(i); // private methods 
     } 
    } 
    return { getMethods : getMethods } 
}(); 

// will return ['getMethods', 'testOne', 'testTwo', 'testThree'] 
Test.getMethods(); 

редактировать:

К сожалению, нет. Набор локальных переменных недоступен с помощью одного ключевого слова auto.

Если вы удалите ключевое слово «var», они будут привязаны к глобальному контексту (обычно к объекту окна), но это единственное поведение, которое, как я знаю, похоже на то, что вы описываете. Однако если бы вы это сделали, было бы много других свойств и методов на этом объекте.

0

Если вы вызываете getMethods(), как это, не статично? Неужели вам нужно будет правильно запустить класс для this, чтобы работать как ожидалось?

var t = new Test(); 
t.getMethods(); 

Если это не работает, пожалуйста, посмотрите на JS Serializer. Я использовал его некоторое время назад для некоторой отладки, и я думаю, что это работало для частных vars.

+2

выше синтаксис эквивалентен: вар Test = новый Object(); Test.getMethods(); – Owen 2008-11-08 23:33:49

2

У Javascript действительно нет понятия частного ничего. Из-за этого, javascript не имеет API отражения как такового. Техника, которую вы используете, не делает их частными, поскольку делает их недоступными; они скрыты, а не частные. Я думаю, вы могли бы что-то сделать, поставив эти методы где-то вручную.

+6

B не следует из A. Языки могут иметь API отражения с конфиденциальностью данных или без них. (Переменные, которые он имеет, даже не «скрыты» или «закрыты», они просто местные.) У Python нет конфиденциальности данных, но он поддерживает мощное отражение. – 2010-12-20 04:31:23

+1

- 1. Ответ вводит в заблуждение. См. Комментарий Гленна «B не следует из A. Языки могут иметь API-интерфейс отражения с конфиденциальностью данных или без него» для получения более подробной информации. – andy 2011-06-21 02:27:38

+1

Javascript может не использовать специфические «частные» идентификаторы, такие как Java, но у него, безусловно, есть понятие частных переменных и методов. Все объявленные как «var a = 1» неявно закрыты внутри функции, так как к ним нельзя получить доступ извне. – 2012-06-11 18:54:30

1

Часть проблемы с вашим тестовым кодом заключается в том, что Test - это объект, созданный вашим оператором return: «{ getMethods : getMethods }« У него нет методов testOne, testTwo или testThree; вместо этого они доступны только в том же пространстве имен, что и исходная функция getMethods.

1

вы можете использовать var that = this; трюк:

var Test = function() { 
    var that = this; 
    function testOne() {} 
    function testTwo() {} 
    function testThree() {} 
    function getMethods() { 
     for (i in that) { 
     alert(i); 
     } 
    } 
    return { getMethods : getMethods } 
}(); 
1

С небольшим изменением в том, как функция определена вы можете добиться того, что вы хотите. Заверните фактическую реализацию функции в объекте буквальным это будет выглядеть так:

(function() { 
    var obj = { 
    // private methods 
    testOne: function() {}, 
    testTwo : function() {}, 
    testThree: function() {}, 
    // public methods 
    getMethods : function() { 
     for (i in this) { 
     alert(i); // shows getMethods, but not private methods 
     } 
    } 
    }; 
    return { getMethods : function(){return obj.getMethods();} } 
})(); 
4

От http://netjs.codeplex.com/SourceControl/changeset/view/91169#1773642

//Reflection 

~function (extern) { 

var Reflection = this.Reflection = (function() { return Reflection; }); 

Reflection.prototype = Reflection; 

Reflection.constructor = Reflection; 

Reflection.getArguments = function (func) { 
    var symbols = func.toString(), 
     start, end, register; 
    start = symbols.indexOf('function'); 
    if (start !== 0 && start !== 1) return undefined; 
    start = symbols.indexOf('(', start); 
    end = symbols.indexOf(')', start); 
    var args = []; 
    symbols.substr(start + 1, end - start - 1).split(',').forEach(function (argument) { 
     args.push(argument); 
    }); 
    return args; 
}; 

extern.Reflection = extern.reflection = Reflection; 

Function.prototype.getArguments = function() { return Reflection.getArguments(this); } 

Function.prototype.getExpectedReturnType = function() { /*ToDo*/ } 

} (this);