这是一个探索性的问题,看看核心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
这几乎就像你需要覆盖Function
类'constructor
方法并从那里访问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 :(得分: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_
属性。这个proto链接只是对构造函数的原型对象的引用,例如,在调用构造函数时的Widget。
当您覆盖Function
构造函数时,您实际上会添加一些内容,这些内容将在您修改_proto_
后创建的每个函数的Function.prototype
属性上。
如果你在你的基类'class'构造函数中创建了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实现了Prototypical Inheritance。我之前谈到的 proto 链接是关键所在。首次创建widget1
时,在构造函数Widget中,method
专门附加到widget1。此method
将无法用于其他实例。但是,原型上的method
在Widget的所有实例中共享。
在运行时,当js解释器看到widget1.method();
时,它首先看到widget1
是否有method
作为其上的属性(js中的对象本质上只是哈希映射,其中这些键被称为“属性”)。在这种情况下,它将实例方法作为属性查找。但是,一旦删除实例方法,它将尝试遵循_proto_
链接,这只是对Widget.prototype的对象引用(在构造函数被调用时)。 Widget.prototype.method已定义;因此,解释器将执行该操作。如果在继续关注method
链接时未找到_proto_
功能,则会出现运行时错误。
答案 1 :(得分: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中引入的,因此只有较新的浏览器才会支持它。