2008-11-08 58 views
28

有沒有辦法從內部獲取JavaScript對象的所有方法(私有,特權或公共)?這裏的樣本對象:Javascript反射

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

這些方法隱藏的技術原因是雙重的。

首先,當您在Test對象上執行一個方法時,「this」將是匿名函數結尾返回的無類型對象,該對象包含每個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(); 

編輯:

不幸的是,沒有。不能通過單個自動關鍵字訪問局部變量集。

如果刪除「var」關鍵字,它們將被附加到全局上下文(通常是窗口對象),但這是我知道的唯一行爲與您所描述的類似。不過,如果你這樣做的話,那個對象上還會有很多其他的屬性和方法。

0

如果調用的getMethods()這樣的,是不是靜態的?當然,您需要正確啓動課程this才能按預期工作?

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

如果這不起作用,請看看JS Serializer。我用了一段時間來進行一些調試,我認爲它適用於私人增值業務。

+2

上面的語法相當於:VAR測試=新的對象(); 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.答案是誤導。有關更多詳細信息,請參閱Glenn的評論「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語句創建的對象:「​​」它沒有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);