简体   繁体   English

ES6静态方法与非静态方法和ES5 OOP

[英]ES6 static method vs non-static and ES5 OOP

I'm a bit confused. 我有点困惑。

If, for example...: 如果,例如...:

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

if the above correct and I got this right, then why the hell would I ever need a static functions? 如果上面的说法正确并且我说得对,那么为什么我需要静态函数? because this: 因为这:

Person.whatEver = function(){
    return this.firstName + " " + this.lastName;
}

is exactly as this, correct?: 就是这样,对吗?:

// it would need to be inside of the class, of course
static whatEver(){
    return this.firstName + " " + this.lastName;
}

While this is equivalent to an ES6 static method, it's not doing what you think: 虽然这相当于ES6静态方法,但它并没有按照您的想法进行:

Person.whatEver = function(){
  return this.firstName + " " + this.lastName;
}

That puts the whatEver function on the Person constructor , not on an instantiated person - and the Person constructor probably does not have a firstName or lastName . 这将whatEver函数放在Person 构造函数上,而不是放在实例化的person - 而Person构造函数可能没有firstNamelastName You were probably thinking of 你可能在考虑

const person = new Person();
person.whatEver = function(){
  return this.firstName + " " + this.lastName;
}

in which case, yes, running code like that every time a Person is instantiated will result in lots of functions (one for each person) rather than just a single function on the prototype. 在这种情况下,是的,每次实例化Person时都会运行这样的代码,这将导致许多函数(每个人一个),而不是原型上的单个函数。

The use for static methods is generally outside of interactions with instantiated objects. 静态方法的使用通常不在与实例化对象的交互之外 Think of when you might want information associated with a class even if nothing has necessarily been instantiated yet. 想想您何时可能需要与类关联的信息,即使尚未实例化任何内容。 For example, you could have a static method on the Person class: 例如,您可以在Person类上使用静态方法:

class Person {
  static canEat() {
    return ['apples', 'bananas', 'carrots'];
  }
  // ...

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? 正确?

No it won't. 不,不会。 You see methods in JS are assigned as references to them. 您会看到JS中的方法被指定为对它们的引用。 This method will be created once and not be repeated again and again for each object. 此方法将创建一次,不会对每个对象反复重复。 They'll point to the same method. 他们会指出相同的方法。 This is a static method only. 这只是一种静态方法。 So both definitions of the whatEver function are statically defining it on the Person class. 因此, whatEver函数的两个定义都是在Person类上静态定义它。

So if you have code like: 所以如果你有像这样的代码:

let firstPerson = new Person();
let secondPerson = new Person();

Both of these objects will have reference to the same instance method(the prototype one) whatEver . 这两个对象都将引用相同的实例方法(原型一) whatEver Now the Person.whatEver static method will also have a single copy which can be called directly on the Person class only and no instance of this class. 现在Person.whatEver静态方法也将有一个副本,只能在Person类上直接调用,而且没有此类的实例。

//contstructor 
function Person () { … } 

//member method
Person.prototype.foo = function () { 
  console.log(this); 
}

//static method
Person.foo = function () { 
   console.log(this);
}

All function definitions are created only once in Memory. 所有函数定义仅在Memory中创建一次。 The diffrence is the »this context«: 差异是»这个背景«:

new Person().foo(); // [Object Person] or Person {}

Person.foo(); // Person () {}

So that is why you cannot access member properties in a static function. 这就是为什么你不能在静态函数中访问成员属性的原因。 this refers to the constructor function not to the instance. this指的是构造函数而不是实例。 Under the hood, using the new operator will do something like this: 在引擎盖下,使用new运算符将执行以下操作:

var obj = Person.call({}) // a new Object is created and passed as the
                          // »this context« and automatically returned.

If you would have: 如果你有:

function Person () {
  this.bar = function () { … }
} 

a new function object would created in Memory for each instance ( new Person() ), but that is the particular property of the prototype chain. 在Memory中为每个实例创建一个新的函数对象( new Person() ),但这是原型链的特定属性。 Calling a method on an instance, will cause the JS interpreter to first search all »own« properties and than go up the prototype chain to find the requested property. 在实例上调用方法将导致JS解释器首先搜索所有“自己的”属性,然后上传原型链以查找所请求的属性。 The prototype is shared by all instances, so its properties are only created once. prototype由所有实例共享,因此其属性仅创建一次。

In ES6 it would look like this: 在ES6中,它看起来像这样:

class Person(){

  static foo () {}

  constructor () {}

  bar () {}

}

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? 正确?

This comes from the misunderstanding of how functions work in Javascript. 这来自于对Javascript中函数如何工作的误解。

In class -based languages, when an instance of a class is created, all the method definitions, including the inherited ones, are copied . 在基于class的语言中,当创建类的实例时,将复制所有方法定义,包括继承的方法定义。

Javascript is not class -based. Javascript不是基于class的。

ES6 added class support, but it's only a sugar, and javascript class doesn't exactly act like classes in Java or C++ (or most other class ic languages) ES6增加了class支持,但它只是一个糖,javascript class并不像Java或C ++(或大多数其他class ic语言)中的class

static methods in Java or C++ doesn't require instantiation, which could be quite useful. Java或C ++中的static方法不需要实例化,这可能非常有用。

In Javascript, since there is no such thing as a class, or instantiation of a class, the methods do not get copied. 在Javascript中,由于没有类或类的实例化,因此不会复制方法。 Only the reference to the function gets copied. 仅复制对函数的引用。

In your code 在你的代码中

Person.whatEver = function(){
    return this.firstName + " " + this.lastName;
}

For easier understanding, you can think of Person as an object with a function whatEver . 为了便于理解,您可以将Person视为具有函数whatEver的对象。 So your 'static' method above is not too different from 所以你上面的'静态'方法与之没有什么不同

let Person = {
  whatEver() {
    return this.firstName + " " + this.lastName;
  },
  talk() {
    return 'I can talk';
  },
};

For example, you can call Person.talk() without instantiation. 例如,您可以在不实例化的情况下调用Person.talk()

However, for your whatEver() function, if you need to access this in it, it's not a good idea to declare it as a static function, because the assumption is that this points to the instantiated object. 然而,对于您的whatEver()函数,如果你需要访问this它,这不是一个好主意,声明为静态函数,因为假设的是, this指向实例化的对象。

Class models don't fit into javascript quite well, and the confusion often originates from that. 类模型不能很好地适应javascript,并且混淆通常源于此。


I want to add one more thing: 我想补充一点:

// so, the following will be shared, and this 
// is the best practice, right?:
Person.prototype.whatEver = function(){
    return this.firstName + " " + this.lastName;
}

This is not true. 这不是真的。 All functions in Javascript is shared, and Person.prototype.whatEver and Person.whatEver are just two different ways of declaring functions. Javascript中的所有函数都是共享的, Person.prototype.whatEverPerson.whatEver只是两种不同的声明函数的方式。

Person.prototype.whatEver can be called on an object you create with new Person(..) , which is a constructor call . 可以使用new Person(..)创建的对象上调用Person.prototype.whatEver ,这是一个构造函数调用 By this I mean when a function is called with new , an empty object gets created, this gets bound to this new object, and the object gets prototype -linked to Person . 我的意思是,当使用new调用函数时,会创建一个空对象, this将绑定到这个新对象,并且该对象将获得prototype - 链接到Person

So when you instantiate it like var p = new Person(..) , and call p.whatEver() , it will try to find whatEver(..) function reference in the prototype chain, and will find one in Person.prototype , which gets called. 所以当你像var p = new Person(..)一样实例化它,并调用p.whatEver() ,它会尝试在原型链中找到whatEver(..)函数引用 ,并在Person.prototype找到一个,被调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM