[英]ES6 static method vs non-static and ES5 OOP
我有点困惑。
如果,例如...:
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
// so, the following will be shared, and this
// is the best practice, right?:
Person.prototype.whatEver = function(){
return this.firstName + " " + this.lastName;
}
// the following will also be shared, but it's
// bad practice, because it will be included in
// each instances and take space(memory) for nothing. correct?
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
如果上面的说法正确并且我说得对,那么为什么我需要静态函数? 因为这:
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
就是这样,对吗?:
// it would need to be inside of the class, of course
static whatEver(){
return this.firstName + " " + this.lastName;
}
虽然这相当于ES6静态方法,但它并没有按照您的想法进行:
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
这将whatEver
函数放在Person
构造函数上,而不是放在实例化的person
- 而Person
构造函数可能没有firstName
或lastName
。 你可能在考虑
const person = new Person();
person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
在这种情况下,是的,每次实例化Person时都会运行这样的代码,这将导致许多函数(每个人一个),而不是原型上的单个函数。
静态方法的使用通常不在与实例化对象的交互之外 。 想想您何时可能需要与类关联的信息,即使尚未实例化任何内容。 例如,您可以在Person类上使用静态方法:
class Person {
static canEat() {
return ['apples', 'bananas', 'carrots'];
}
// ...
以下内容也将被共享,但这是不好的做法,因为它将被包含在每个实例中并占用空间(内存)。 正确?
不,不会。 您会看到JS中的方法被指定为对它们的引用。 此方法将创建一次,不会对每个对象反复重复。 他们会指出相同的方法。 这只是一种静态方法。 因此, whatEver
函数的两个定义都是在Person类上静态定义它。
所以如果你有像这样的代码:
let firstPerson = new Person();
let secondPerson = new Person();
这两个对象都将引用相同的实例方法(原型一) whatEver
。 现在Person.whatEver
静态方法也将有一个副本,只能在Person
类上直接调用,而且没有此类的实例。
//contstructor
function Person () { … }
//member method
Person.prototype.foo = function () {
console.log(this);
}
//static method
Person.foo = function () {
console.log(this);
}
所有函数定义仅在Memory中创建一次。 差异是»这个背景«:
new Person().foo(); // [Object Person] or Person {}
Person.foo(); // Person () {}
这就是为什么你不能在静态函数中访问成员属性的原因。 this
指的是构造函数而不是实例。 在引擎盖下,使用new
运算符将执行以下操作:
var obj = Person.call({}) // a new Object is created and passed as the
// »this context« and automatically returned.
如果你有:
function Person () {
this.bar = function () { … }
}
在Memory中为每个实例创建一个新的函数对象( new Person()
),但这是原型链的特定属性。 在实例上调用方法将导致JS解释器首先搜索所有“自己的”属性,然后上传原型链以查找所请求的属性。 prototype
由所有实例共享,因此其属性仅创建一次。
在ES6中,它看起来像这样:
class Person(){
static foo () {}
constructor () {}
bar () {}
}
以下内容也将被共享,但这是不好的做法,因为它将被包含在每个实例中并占用空间(内存)。 正确?
这来自于对Javascript中函数如何工作的误解。
在基于class
的语言中,当创建类的实例时,将复制所有方法定义,包括继承的方法定义。
Javascript不是基于class
的。
ES6增加了class
支持,但它只是一个糖,javascript class
并不像Java或C ++(或大多数其他class
ic语言)中的class
Java或C ++中的static
方法不需要实例化,这可能非常有用。
在Javascript中,由于没有类或类的实例化,因此不会复制方法。 仅复制对函数的引用。
在你的代码中
Person.whatEver = function(){
return this.firstName + " " + this.lastName;
}
为了便于理解,您可以将Person
视为具有函数whatEver
的对象。 所以你上面的'静态'方法与之没有什么不同
let Person = {
whatEver() {
return this.firstName + " " + this.lastName;
},
talk() {
return 'I can talk';
},
};
例如,您可以在不实例化的情况下调用Person.talk()
。
然而,对于您的whatEver()
函数,如果你需要访问this
它,这不是一个好主意,声明为静态函数,因为假设的是, this
指向实例化的对象。
类模型不能很好地适应javascript,并且混淆通常源于此。
我想补充一点:
// so, the following will be shared, and this
// is the best practice, right?:
Person.prototype.whatEver = function(){
return this.firstName + " " + this.lastName;
}
这不是真的。 Javascript中的所有函数都是共享的, Person.prototype.whatEver
和Person.whatEver
只是两种不同的声明函数的方式。
可以使用new Person(..)
创建的对象上调用Person.prototype.whatEver
,这是一个构造函数调用 。 我的意思是,当使用new
调用函数时,会创建一个空对象, this
将绑定到这个新对象,并且该对象将获得prototype
- 链接到Person
。
所以当你像var p = new Person(..)
一样实例化它,并调用p.whatEver()
,它会尝试在原型链中找到whatEver(..)
函数引用 ,并在Person.prototype
找到一个,被调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.