JavaScript:Class.method 与 Class.prototype.method

Posted

技术标签:

【中文标题】JavaScript:Class.method 与 Class.prototype.method【英文标题】:JavaScript: Class.method vs. Class.prototype.method 【发布时间】:2010-12-10 17:51:39 【问题描述】:

以下两个声明有什么区别?

Class.method = function ()  /* code */ 
Class.prototype.method = function ()  /* code using this.values */ 

是否可以将第一条语句视为静态方法的声明,将第二条语句视为实例方法的声明?

【问题讨论】:

【参考方案1】:

是的,第一个函数与constructor function 的对象实例没有关系,您可以将其视为'静态方法'

javascript 中,函数是 first-class 对象,这意味着您可以像对待任何对象一样对待它们,在这种情况下,您只是为 函数对象添加一个属性

第二个函数,当您扩展构造函数原型时,它将可用于使用new 关键字创建的所有对象实例,并且该函数内的上下文(this 关键字)将引用您调用它的实际对象实例。

考虑这个例子:

// constructor function
function MyClass () 
  var privateVariable; // private member only available within the constructor fn

  this.privilegedMethod = function ()  // it can access private members
    //..
  ;


// A 'static method', it's just like a normal function 
// it has no relation with any 'MyClass' object instance
MyClass.staticMethod = function () ;

MyClass.prototype.publicMethod = function () 
  // the 'this' keyword refers to the object instance
  // you can access only 'privileged' and 'public' members
;

var myObj = new MyClass(); // new object instance

myObj.publicMethod();
MyClass.staticMethod();

【讨论】:

但是为什么 Function.prototype.method == Function.method 呢? @Raghavendra 不是 @Menda 你的链接失效了【参考方案2】:

当您创建多个 MyClass 实例时,您仍然只有一个 publicMethod 实例在内存中,但在 privilegedMethod 的情况下,您最终会创建大量实例,而 staticMethod 与对象实例没有关系。

这就是原型节省内存的原因。

另外,如果你改变了父对象的属性,如果子对象的对应属性没有改变,它就会被更新。

【讨论】:

"另外,如果你改变了父对象的属性,如果子对象的对应属性没有改变,它会被更新。不知道你是什么意思。是否只有在更改父对象的原型属性时才如此?【参考方案3】:

对于视觉学习者,在定义函数时不带.prototype

ExampleClass = function();
ExampleClass.method = function(customString)
             console.log((customString !== undefined)? 
                          customString : 
                          "called from func def.");
ExampleClass.method(); // >> output: `called from func def.`  

var someInstance = new ExampleClass();
someInstance.method('Called from instance');
    // >> error! `someInstance.method is not a function`  

同样的代码,如果添加了.prototype

ExampleClass.prototype.method = function(customString)
             console.log((customString !== undefined)? 
                          customString : 
                          "called from func def.");
ExampleClass.method();  
      // > error! `ExampleClass.method is not a function.`  

var someInstance = new ExampleClass();
someInstance.method('Called from instance');
                 // > output: `Called from instance`

为了更清楚,

ExampleClass = function();
ExampleClass.directM = function()  //M for method
ExampleClass.prototype.protoM = function()

var instanceOfExample = new ExampleClass();

ExampleClass.directM();     ✓ works
instanceOfExample.directM();   x Error!

ExampleClass.protoM();     x Error!
instanceOfExample.protoM();  ✓ works

****注意上面的例子, someInstance.method() 不会被执行为, ExampleClass.method() 导致错误 & 执行无法继续。 但为了便于说明和理解,我保留了这个顺序。****

chrome developer consoleJS Bin 生成的结果 单击上面的 jsbin 链接以单步执行代码。 使用 ctrl+/

切换评论部分

【讨论】:

【参考方案4】:

是的,第一个是static method,也称为class method,而第二个是instance method

考虑以下示例,以更详细地理解它。

在 ES5 中

function Person(firstName, lastName) 
   this.firstName = firstName;
   this.lastName = lastName;


Person.isPerson = function(obj) 
   return obj.constructor === Person;


Person.prototype.sayHi = function() 
   return "Hi " + this.firstName;

在上面的代码中,isPerson是静态方法,而sayHiPerson的实例方法。

下面是如何从Person构造函数创建一个对象。

var aminu = new Person("Aminu", "Abubakar");

使用静态方法isPerson

Person.isPerson(aminu); // will return true

使用实例方法sayHi

aminu.sayHi(); // will return "Hi Aminu"

在 ES6 中

class Person 
   constructor(firstName, lastName) 
      this.firstName = firstName;
      this.lastName = lastName;
   

   static isPerson(obj) 
      return obj.constructor === Person;
   

   sayHi() 
      return `Hi $this.firstName`;
   

看看static关键字是如何被用来声明静态方法isPerson的。

创建Person类的对象。

const aminu = new Person("Aminu", "Abubakar");

使用静态方法isPerson

Person.isPerson(aminu); // will return true

使用实例方法sayHi

aminu.sayHi(); // will return "Hi Aminu"

注意:这两个示例本质上是相同的,JavaScript 仍然是一种无类语言。 ES6 中引入的class 主要是现有基于原型的继承模型的语法糖。

【讨论】:

“在 ES6 中”你只描述了一个语法糖。这不是“ES2015”(请大家停止使用 ES6,使用正确的术语 ES2015)的方式。这只是另一种方式,在我看来是不正确的方式。 @KarlMorrison Aminu 没有写“做这件事的方式”,你只是自己写的,并对此表示反对。关于 ES6 与 ES2015,您的观点可能是公平的,但在对话中,人们通常会采用更短的约定来提高效率,所以我认为从写作中删除它是不可能的,或者肯定是可取的。 感谢您回答的 ES6 部分;这澄清了很多,尤其是结合上面的2个“公共+特权”答案时。但是,我对您的 obj.constructor === Persontrue 的示例彻底感到困惑... Whaaaat?类实例的构造函数=== 类本身如何...? (这就像说集合的子集就是集合本身,等等......) Ohhh... 这就是说从字面上看,构造函数就是 JS 类在一天结束时真正的全部吗?其他所有东西要么堆积到构造函数中,要么完全是一个与类隔离的静态构造,除了名称/概念(就像一个隐含的“this”显然可用)? (因此,我认为是集合的子集实际上不是子集。) @Andrew 超现实的感觉或许来自于此:在 JavaScript 中,类和构造函数是一回事。顺便说一句,我一直回到this diagram。这很奇怪,但奖励学习。最终,它真的让我对 JavaScript 执行类或假装类的方式感到困惑。理解构造函数属性的关键是 John Sonderson 的评论:b.constructor 就像任何类属性解析为 b.__proto__.constructor 并因此指向 Foo【参考方案5】:

A.静态方法:

      Class.method = function ()  /* code */ 
    method() 这里是一个函数property添加到另一个function(这里是Class)。 您可以通过类/函数名称直接访问method()。 Class.method(); 不需要创建任何对象/实例 (new Class()) 来访问method()。因此,您可以将其称为静态方法。

B.原型方法(所有实例共享):

     Class.prototype.method = function ()  /* code using this.values */ 
    method() 这里是一个函数property添加到另一个function protype(这里是Class.prototype)。 您可以 要么通过类名对象/实例直接访问 (new Class()) . 附加优势 - 这种方法()定义方式将在内存中创建 一个方法()的副本,并将在 所有之间共享 strong> 从Class 创建的对象/实例

C.类方法(每个实例都有自己的副本):

   function Class () 
      this.method = function ()  /* do something with the private members */;
   
    method() 这里是在另一个函数(这里是类)中定义的方法。 您不能通过类/函数名称直接访问method()。 Class.method();需要为 method() 访问创建一个对象/实例 (new Class())。 这种 method() 定义方式将为使用构造函数 (new Class()) 创建的每个对象 创建一个 method() 的唯一副本。 附加优势 - method() 作用域的 Bcos 拥有访问构造函数中声明的 local 成员(也称为 private 成员)的完全权限(此处类)

例子:

    function Class() 
        var str = "Constructor method"; // private variable
        this.method = function ()  console.log(str); ;
    
    Class.prototype.method = function()  console.log("Prototype method"); ;
    Class.method = function()  console.log("Static method"); ;

    new Class().method();     // Constructor method
    // Bcos Constructor method() has more priority over the Prototype method()

    // Bcos of the existence of the Constructor method(), the Prototype method 
    // will not be looked up. But you call it by explicity, if you want.
    // Using instance
    new Class().constructor.prototype.method(); // Prototype method

    // Using class name
    Class.prototype.method(); // Prototype method

    // Access the static method by class name
    Class.method();           // Static method

【讨论】:

A. “无需创建任何对象/实例(new Class())来访问 method()。因此您可以将其称为静态方法。”是否可以从实例访问静态方法?如果有怎么办。消除这种歧义会很好。 B. “您可以通过类名或对象/实例(new Class())直接访问。”我认为添加一个通过类名(Class.prototype.method())访问的示例来澄清会很有帮助。一开始我很困惑,因为我知道 Class.method() 不适用于原型方法。您的回答对我的理解很有帮助,非常感谢。

以上是关于JavaScript:Class.method 与 Class.prototype.method的主要内容,如果未能解决你的问题,请参考以下文章

javascript Class.method vs Class.prototype.method(类方法和对象方法)

为啥有些人在通信中使用 Class#method 而不是 Class.method?

错误索引方法“Class.Method”无法将参数“log”绑定到类型 TraceWriter

Python OOP-static method,class method and instance method

ABAP中Class/method对应program name获取

017: class, objects and instance: class method