2011-10-13 103 views
2

這是一個探索性問題,看看核心JavaScript的東西是如何工作的。我意識到約定是不覆蓋任何核心JavaScript類,但我似乎無法繞過這一個。是否有可能將實例方法添加到JavaScript中的所有「類」中?

你可以創造什麼通過向核心Function原型這樣就像在JavaScript「類方法」:

Function.prototype.class_method = function() { 
    console.log("class method called") 
} 

var User; 
User = (function() { 
    function User() {} 
    return User; 
})(); 

User.class_method(); // "class method called" 

我的問題是,有沒有辦法在一個類似添加「實例方法」辦法?一些瘋狂這樣的,但什麼是下面不工作(或任何意義):

alias = Function.prototype.constructor; 
Function.prototype.constructor = function() { 
    child = this; 
    child.prototype.instance_method = function() { 
    console.log("instance method called"); 
    } 
    alias.apply(child); 
} 

var user = new User(); 
user.instance_method(); // method doesn't exist 

這幾乎就像你需要重寫Functionconstructor方法,並從那裏訪問prototype。這可能嗎?

如果添加到Object.prototype這樣,它工作:

Object.prototype.instance_method = function() { 
    console.log("instance method"); 
} 

var user = new User(); 
user.instance_method(); // "instance method called" 

但是,這似乎並沒有任何的權利,主要是因爲看到從console.log({});變化Node.js的控制檯輸出是混亂:

console.log({}); 
// {}; 

Object.prototype.instance_method = function() { 
    console.log("instance method"); 
} 

console.log({}); 
// {"instance_method": [Function]} 
+0

實際上,你不會稱它們爲「類」,它們是「構造函數」。這也可以幫助你https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create – Deeptechtons

回答

2

如果您正在使用Node.js的,你應該能夠使用Object.defineProperty[MDN],使新屬性不可枚舉

Object.defineProperty(Object.prototype, 'instance_Method', { 
    value: function() { 
     console.log("instance method"); 
    }, 
    enumerable: false // it's already the default 
}); 

這是在ECMAScript5推出,所以只有新的瀏覽器將支持它。

2

瞭解原型何時開始起作用很重要。它只是一個對象,是一個函數的屬性。它只有在使用new關鍵字時纔有意義。例如:

var Widget = function(val) { 
     this.value = val; 
    }; 
    Widget.prototype.getValue = function() { 
     return this.value; 
    }; 
    var widget1 = new Widget('test'); 
    widget1.getValue(); // test 
    var widget2 = new Widget('test2'); 
    widget2.getValue(); // test2 

當使用new,將JS解釋將創建的實例隱藏_proto_屬性。這個原型鏈接只是對構造函數的原型對象的引用,例如構造函數被調用時的Widget。

當您覆蓋構造函數Function時,實際上是在修改Function.prototype後創建的每個函數的_proto_屬性中添加了一些內容。

如果您在基類的「構造函數」中聲明瞭child.prototype... = ...,那麼在「實例化」子元素之前,該原型將沒有意義,例如var child = new child();

很好Resource

要獲得關於「實例方法」的問題,你只需要像做以下幾點:

var Widget = function() { 
     this.method = function() { 
      return 'instance method'; 
     }; 
    }; 
    Widget.prototype.method = function() { 
     return 'class method'; 
    }; 
    var widget1 = new Widget(); 
    widget1.method(); // instance method 
    delete widget1.method; 
    widget1.method(); // class method 

這是由於JavaScript的執行原型繼承。我之前談到的鏈接proto是這裏的關鍵。當第一次創建widget1時,在構造函數Widget中,method特別附加到了widget1。此method將不可用於其他實例。但是,原型上的method在所有Widget實例中共享。

在運行時,當JS解釋看到widget1.method();,它首先看到如果widget1具有method直接在其上的屬性(在JS對象僅僅包含HashMap在本質上,其中,所述密鑰被稱爲「屬性」)。它在這種情況下找到實例方法作爲屬性。但是,一旦刪除實例方法,它將嘗試遵循_proto_鏈接,該鏈接僅是對Widget.prototype的對象引用(在構造函數被調用時)。定義Widget.prototype.method;因此,解釋器將執行該操作。如果在繼續遵循_proto_鏈接時沒有找到method函數,那將是一個運行時錯誤。

+0

請注意,'instanceof'運算符不依賴於'constructor'屬性,即使你重新定義了'Function .prototype.constructor'檢查'(function(){})instanceof Function'將返回'true'。 'instanceof'運算符直接檢查內部原型鏈,你會觀察到的副作用是所有的函數對象都繼承了重新定義的'constructor'屬性,例如'(function(){} .constructor)'。 – CMS

+0

@CMS - 是的,你說得對。我編輯了它。 – Ryan

相關問題