2011-10-13 88 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

相关问题