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 console
和JS 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
是静态方法,而sayHi
是Person
的实例方法。
下面是如何从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 === Person
是 true
的示例彻底感到困惑... 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