是否可以将实例方法添加到所有的“类”中?在JavaScript

Is it possible to add instance methods to all "classes" in JavaScript?

本文关键字:JavaScript 实例方法 添加 是否      更新时间:2023-09-26

这更像是一个探索性的问题,看看JavaScript的核心内容是如何工作的。我意识到惯例是不重写任何核心JavaScript类,但我似乎就是无法理解这个。

你可以在JavaScript中创建类似于"类方法"的东西,通过像这样添加核心Function原型:

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]}

如果你正在使用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中引入的,所以只有较新的浏览器才会支持。

了解原型何时起作用是很重要的。它只是一个对象,是一个函数的属性。它只有在使用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();

A great 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的原型继承的实现。我之前提到的原型链接是这里的关键。当widget1首次在构造函数Widget中创建时,method被专门附加到widget1。此method将不可用于其他实例。但是,原型上的method在Widget的所有实例之间是共享的。

在运行时,当js解释器看到widget1.method();时,它首先看到widget1是否直接将method作为其属性(js中的对象本质上只是哈希映射,其中的键被称为"属性")。在本例中,它将实例方法作为属性查找。但是,一旦删除实例方法,它将尝试遵循_proto_链接,该链接只是对Widget的对象引用。原型(在调用构造函数时)。定义了Widget.prototype.method;因此,解释器将执行该语句。如果在继续遵循_proto_链接时没有找到method函数,则会出现运行时错误

相关文章: